Blatantly Bad Weapon Prediction?

Hey guys, so I have a question that peers into prediction and basic networking within Lua generated weapons.

It’s a pretty straightforward question, and I’m sure some of you might have wondered yourself, but, why is weapon prediction so awful in Garry’s Mod?

I mean sure, in singleplayer, there’s nothing to worry about, but once you play any multiplayer server, there’s always noticeable problems, such as reload counts skipping, animations playing between milliseconds, and sometimes worse, seconds, effects being unbelievably delayed.

So I’m going to humiliate myself and just say that I’m a giant idiot who doesn’t know what’s really going on, but why is this such a persistent problem with Garry’s Mod?

I figure that if the internal weapon code is right, then the SWEPs themselves should behave just like the hard coded variants, considering the SWEP code is shared in most instances.

Go ahead and give me boxes to package my weapons in if I’m missing something everyone already knows.

I have massive problems with it too. In fact the CSS sweps that Garry has distributed with GMod seems to have problems with it. The thing is, you have no control over who the messages actually get sent to when you send a weapon animation from the server, and half of the clientside functions don’t even work. It’s damn annoying.

I feel your pain. It’s just silly, some things that happen (SendWeaponAnim clientside = fucked up anim, serverside = only playable once/laggy, shared = laggy)

Wow, so like, this is all just something we all know but never talk about? There has to be an aid to this problem.

If you make the weapons right, you can severely minimize any of these problems. My weapon base I made for my servers seems to handle very well…

This. GMod doesn’t know what it’s supposed to predict and when. You need to explicitly tell it.

Making everything shared should work, yes? That way, the client receives all the commands the server does in order to predict.

Doesn’t work. Try it yourself.


I would like to see the code behind this (if not actual Lua, then pseudo-code).

Here’s a snippet of the primary fire/shoot bullets.

[lua]function SWEP:PrimaryAttack()
if ( !self:CanShootWeapon() ) then return end
if ( !self:CanPrimaryAttack() ) then return end

self.Weapon:SetNextPrimaryFire( CurTime() + self.Primary.Delay )

self.Weapon:ShootBullet( self.Primary.NumShots, self.Primary.Cone/self:GetStanceAccuracyBonus() )
self.Weapon:TakePrimaryAmmo( 1 )

if IsFirstTimePredicted() and self.Owner:IsValid() then --Predict that motha' fucka'


	self.Weapon:EmitSound( self.Primary.Sound, 100, math.random(95,105) )
	local bonus = self:GetStanceAccuracyBonus()
	if ( CLIENT || SinglePlayer()) then
		local eyeang = self.Owner:EyeAngles()
		eyeang.pitch = eyeang.pitch - self.Primary.Recoil/bonus/1.5
		eyeang.yaw = eyeang.yaw - math.Rand(-1,1)*self.Primary.Recoil/bonus/1.5
		self.Owner:SetEyeAngles( eyeang )

	if self.Weapon:GetNetworkedBool( "Ironsights", false ) == false then
		self.Owner:ViewPunch( Angle( -self.Primary.Recoil/bonus, math.Rand(-1,1)*self.Primary.Recoil, 0))
		self.Owner:ViewPunch( Angle( -self.Primary.Recoil/bonus/2, math.Rand(-1,1)*self.Primary.Recoil/2, 0))

if ( (SinglePlayer() && SERVER) || CLIENT ) then
	self.Weapon:SetNetworkedFloat( "LastShootTime", CurTime() )


function SWEP:ShootBullet( num_bullets, aimcone )

self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
self.Owner:SetAnimation( PLAYER_ATTACK1 )

if !IsFirstTimePredicted() then return end

local effectdata = EffectData()
effectdata:SetOrigin( self.Owner:GetShootPos() )
effectdata:SetEntity( self.Weapon )
effectdata:SetStart( self.Owner:GetShootPos() )
effectdata:SetNormal( self.Owner:GetAimVector() )
effectdata:SetAttachment( 1 )
util.Effect( "gunsmoke", effectdata )

if self.MuzzleEffect and self.MuzzleEffect != nil then
	local effectdata = EffectData()
	effectdata:SetOrigin( self.Owner:GetShootPos() )
	effectdata:SetEntity( self.Weapon )
	effectdata:SetStart( self.Owner:GetShootPos() )
	effectdata:SetNormal( self.Owner:GetAimVector() )
	effectdata:SetAttachment( 1 )
	util.Effect( self.MuzzleEffect, effectdata )

local bullet = {}
bullet.Num 			= num_bullets
bullet.Src 			= self.Owner:GetShootPos()
bullet.Dir 			= self.Owner:GetAimVector()
bullet.Spread 		= Vector( aimcone, aimcone, 0 )
bullet.Tracer		= 5
bullet.Force		= self.Primary.BulletForce
if type( self.Primary.Damage ) == "table" then
	bullet.Damage 	= math.random( self.Primary.Damage[1], self.Primary.Damage[2] )
	bullet.Damage 	= self.Primary.Damage
bullet.AmmoType 	= self.Primary.Ammo
bullet.Callback = function ( attacker, tr, dmginfo )
	self.Weapon:BulletCallback( attacker, tr, dmginfo, 0 )

self.Owner:FireBullets( bullet )


All shared, right?

And is that effect business basically a manual version of self:MuzzleFlash()?

And ply:ViewPunch has no effect clientside.

Yes, all shared.

Yes, to effects.

Viewpunch works fine clientside…

Has never ever worked for me clientside, either singleplayer, listen server or on a dedi.

Working fine for me… :confused:

Did it work before the engine update?

I believe so. I’ll have to double check if it is working clientside in a minute.


Just tested it on my server. ViewPunch is definitely working fine.

How odd. I’ll have another look when I next do some GMod dev. But when I tested it, I tested pretty thoroughly and it most certainly had no effect clientside. Oh well.

The predicted_viewmodel entity is to blame. If you do it entirely clientside with a cmodel, it works perfectly.

The bug has been around for a while in regards to the entity.

I’m sorry but I derived code directly from the Source SDK to write these weapons.

I hope your meaning is: if you write the weapons in a way which Garry’s Mod can tolerate.


I don’t understand this at all, really. GMod isn’t doing anything special with the weapons. You’re using wrapper functions which are derived from straight out of the game; theoretically, if there is no tampering with said functions, then writing a weapon directly from the code out of the Source SDK translated to Lua should work just the same as their hard-coded counterparts, unless the methodology of running Lua methods from within the SWEP object somehow throws everything off.


It might have been an engine update, when you check the root of the function, it’s definitely shared, but I remember distinctively that the client-side function did nothing, it was empty.


you got to be kidding, garry’s account there is even closed. he dosent check that at all i think


That post was from 8 months ago. It’s an old issue is what I mean.