Getting an error from one of my SWEPs

So I’m getting this error…




[ERROR] gamemodes/terrortown/entities/weapons/weapon_ttt_stunbaton.lua:282: Tried to use a NULL entity!
  1. __index - [C]:-1
   2. unknown - gamemodes/terrortown/entities/weapons/weapon_ttt_stunbaton.lua:282

Timer Failed! [Simple][@gamemodes/terrortown/entities/weapons/weapon_ttt_stunbaton.lua (line 282)]


From this SWEP…




AddCSLuaFile()

SWEP.HoldType			= "melee"

if CLIENT then
   SWEP.PrintName			= "Stun Baton"

   SWEP.Slot				= 0

   SWEP.Icon = "vgui/ttt/icon_cbar"   
   SWEP.ViewModelFOV = 62
end

SWEP.UseHands			= true
SWEP.Base				= "weapon_tttbase"
SWEP.ViewModel = Model("models/weapons/v_stunstick.mdl") --The model while being held
SWEP.WorldModel = Model("models/weapons/w_stunbaton.mdl")
SWEP.Weight			= 5
SWEP.DrawCrosshair		= false
SWEP.ViewModelFlip		= false
SWEP.Primary.Damage = 25
SWEP.Primary.ClipSize		= -1
SWEP.Primary.DefaultClip	= -1
SWEP.Primary.Automatic		= true
SWEP.Primary.Delay = 0.5
SWEP.Primary.Ammo		= "none"
SWEP.Secondary.ClipSize		= -1
SWEP.Secondary.DefaultClip	= -1
SWEP.Secondary.Automatic	= true
SWEP.Secondary.Ammo		= "none"
SWEP.Secondary.Delay = 5

SWEP.Kind = WEAPON_MELEE

SWEP.NoSights = true
SWEP.IsSilent = true

SWEP.AutoSpawnable = false

SWEP.AllowDelete = false -- never removed for weapon reduction
SWEP.AllowDrop = false

local sound_single = Sound("weapons/stunstick/stunstick_swing1.wav")
local sound_hit = Sound("weapons/stunstick/stunstick_fleshhit2.wav")
local sound_open = Sound("DoorHandles.Unlocked3")

if SERVER then
   CreateConVar("ttt_crowbar_unlocks", "1", FCVAR_ARCHIVE)
   CreateConVar("ttt_crowbar_pushforce", "395", FCVAR_NOTIFY)
end

-- only open things that have a name (and are therefore likely to be meant to
-- open) and are the right class. Opening behaviour also differs per class, so
-- return one of the OPEN_ values
local function OpenableEnt(ent)
   local cls = ent:GetClass()
   if ent:GetName() == "" then
      return OPEN_NO
   elseif cls == "prop_door_rotating" then
      return OPEN_ROT
   elseif cls == "func_door" or cls == "func_door_rotating" then
      return OPEN_DOOR
   elseif cls == "func_button" then
      return OPEN_BUT
   elseif cls == "func_movelinear" then
      return OPEN_NOTOGGLE
   else
      return OPEN_NO
   end
end


local function CrowbarCanUnlock(t)
   return not GAMEMODE.crowbar_unlocks or GAMEMODE.crowbar_unlocks[t]
end

-- will open door AND return what it did
function SWEP:OpenEnt(hitEnt)
   -- Get ready for some prototype-quality code, all ye who read this
   if SERVER and GetConVar("ttt_crowbar_unlocks"):GetBool() then
      local openable = OpenableEnt(hitEnt)

      if openable == OPEN_DOOR or openable == OPEN_ROT then
         local unlock = CrowbarCanUnlock(openable)
         if unlock then
            hitEnt:Fire("Unlock", nil, 0)
         end

         if unlock or hitEnt:HasSpawnFlags(256) then
            if openable == OPEN_ROT then
               hitEnt:Fire("OpenAwayFrom", self.Owner, 0)
            end
            hitEnt:Fire("Toggle", nil, 0)
         else
            return OPEN_NO
         end
      elseif openable == OPEN_BUT then
         if CrowbarCanUnlock(openable) then
            hitEnt:Fire("Unlock", nil, 0)
            hitEnt:Fire("Press", nil, 0)
         else
            return OPEN_NO
         end
      elseif openable == OPEN_NOTOGGLE then
         if CrowbarCanUnlock(openable) then
            hitEnt:Fire("Open", nil, 0)
         else
            return OPEN_NO
         end
      end
      return openable
   else
      return OPEN_NO
   end
end

function SWEP:PrimaryAttack()
   self.Weapon:SetNextPrimaryFire( CurTime() + self.Primary.Delay )

   if not IsValid(self.Owner) then return end

   if self.Owner.LagCompensation then -- for some reason not always true
      self.Owner:LagCompensation(true)
   end

   local spos = self.Owner:GetShootPos()
   local sdest = spos + (self.Owner:GetAimVector() * 70)

   local tr_main = util.TraceLine({start=spos, endpos=sdest, filter=self.Owner, mask=MASK_SHOT_HULL})
   local hitEnt = tr_main.Entity
	
	if IsValid(hitEnt) or tr_main.HitWorld then
		self.Weapon:EmitSound(sound_hit)
	else
		self.Weapon:EmitSound(sound_single)
	end

   if IsValid(hitEnt) or tr_main.HitWorld then
      self.Weapon:SendWeaponAnim( ACT_VM_HITCENTER )

      if not (CLIENT and (not IsFirstTimePredicted())) then
         local edata = EffectData()
         edata:SetStart(spos)
         edata:SetOrigin(tr_main.HitPos)
         edata:SetNormal(tr_main.Normal)
         edata:SetSurfaceProp(tr_main.SurfaceProps)
         edata:SetHitBox(tr_main.HitBox)
         --edata:SetDamageType(DMG_CLUB)
         edata:SetEntity(hitEnt)

         if hitEnt:IsPlayer() or hitEnt:GetClass() == "prop_ragdoll" then
            util.Effect("BloodImpact", edata)

            -- does not work on players rah
            --util.Decal("Blood", tr_main.HitPos + tr_main.HitNormal, tr_main.HitPos - tr_main.HitNormal)

            -- do a bullet just to make blood decals work sanely
            -- need to disable lagcomp because firebullets does its own
            self.Owner:LagCompensation(false)
            self.Owner:FireBullets({Num=1, Src=spos, Dir=self.Owner:GetAimVector(), Spread=Vector(0,0,0), Tracer=0, Force=1, Damage=0})
         else
            util.Effect("Impact", edata)
         end
      end
   else
      self.Weapon:SendWeaponAnim( ACT_VM_MISSCENTER )
   end


   if CLIENT then
      -- used to be some shit here
   else -- SERVER

      -- Do another trace that sees nodraw stuff like func_button
      local tr_all = nil
      tr_all = util.TraceLine({start=spos, endpos=sdest, filter=self.Owner})
      
      self.Owner:SetAnimation( PLAYER_ATTACK1 )

      if hitEnt and hitEnt:IsValid() then
         if self:OpenEnt(hitEnt) == OPEN_NO and tr_all.Entity and tr_all.Entity:IsValid() then
            -- See if there's a nodraw thing we should open
            self:OpenEnt(tr_all.Entity)
         end

         local dmg = DamageInfo()
         dmg:SetDamage(self.Primary.Damage)
         dmg:SetAttacker(self.Owner)
         dmg:SetInflictor(self.Weapon)
         dmg:SetDamageForce(self.Owner:GetAimVector() * 1500)
         dmg:SetDamagePosition(self.Owner:GetPos())
         dmg:SetDamageType(DMG_CLUB)

         hitEnt:DispatchTraceAttack(dmg, spos + (self.Owner:GetAimVector() * 3), sdest)

--         self.Weapon:SendWeaponAnim( ACT_VM_HITCENTER )         

--         self.Owner:TraceHullAttack(spos, sdest, Vector(-16,-16,-16), Vector(16,16,16), 30, DMG_CLUB, 11, true)
--         self.Owner:FireBullets({Num=1, Src=spos, Dir=self.Owner:GetAimVector(), Spread=Vector(0,0,0), Tracer=0, Force=1, Damage=20})
      
      else
--         if tr_main.HitWorld then
--            self.Weapon:SendWeaponAnim( ACT_VM_HITCENTER )
--         else
--            self.Weapon:SendWeaponAnim( ACT_VM_MISSCENTER )
--         end

         -- See if our nodraw trace got the goods
         if tr_all.Entity and tr_all.Entity:IsValid() then
            self:OpenEnt(tr_all.Entity)
         end
      end
   end

   if self.Owner.LagCompensation then
      self.Owner:LagCompensation(false)
   end
end

--[[local canPickUpThatCan = 1
function SWEP:SecondaryAttack()
	if canPickUpThatCan == 1 then
		local soundnumber = math.Round(math.random(1,3))
		if SERVER then
			local canEnt = ents.Create("prop_physics")
			
			if IsValid(canEnt) then
				local plyModel = self.Owner:GetModel()
				
				canEnt:SetModel("models/props_junk/popcan01a.mdl")
				canEnt:SetPos(self.Owner:EyePos())
				canEnt:Spawn()
				
				canEnt:GetPhysicsObject():SetVelocity(self.Owner:GetForward() * 500)
				
				timer.Simple(60, function() canEnt:Remove() end )
				
				self.Owner:SetModel("models/player/police.mdl")
				timer.Simple(1.5, function() self.Owner:SetModel(plyModel) end )
			end
		end
		
		canPickUpThatCan = 0
		timer.Simple(3, function() canPickUpThatCan = 1 end )
		if soundnumber == 1 then
			self.Weapon:EmitSound("npc/metropolice/vo/pickupthecan1.wav")
		elseif soundnumber == 2 then
			self.Weapon:EmitSound("npc/metropolice/vo/pickupthecan2.wav")
		else
			self.Weapon:EmitSound("npc/metropolice/vo/pickupthecan3.wav")
		end
	end
end]]

function SWEP:SecondaryAttack()
	if self.Owner.cantCan then return end
		
	if SERVER then

		local canEnt = ents.Create("prop_physics")			
		canEnt:SetModel("models/props_junk/popcan01a.mdl")
		canEnt:SetPos( self.Owner:EyePos() )
		canEnt:SetCollisionGroup( 15 )
		canEnt:Spawn()
		
		local phys = canEnt:GetPhysicsObject()
		if IsValid(phys) then
			phys:SetVelocity(self.Owner:GetForward() * 500)
		end
		
		timer.Simple(60, function() if IsValid(canEnt) then canEnt:Remove() end end)
		
		local oldModel = self.Owner:GetModel()
		self.Owner:SetModel("models/player/police.mdl")

		timer.Simple(1.5, function() if IsValid(self.Owner) then self.Owner:SetModel(oldModel) end end)

	end
	
	self.Owner.cantCan = true
	timer.Simple(3, function() self.Owner.cantCan = nil end )

	self.Weapon:EmitSound( "npc/metropolice/vo/pickupthecan" .. math.Round(math.random( 1, 3 )) .. ".wav" )

end

function SWEP:GetClass()
	return "weapon_ttt_stunbaton"
end

function SWEP:OnDrop()
	self:Remove()
end


The error happens when someone does a secondary attack, then they immediately die. I don’t know how to fix it though. Any help?

Always check if self.Owner, or any entity in general, is valid after you create a timer.

This is the new code for the SecondaryAttack



function SWEP:SecondaryAttack()
	if self.Owner.cantCan then return end
		
	if SERVER then

		local canEnt = ents.Create("prop_physics")			
		canEnt:SetModel("models/props_junk/popcan01a.mdl")
		canEnt:SetPos( self.Owner:EyePos() )
		canEnt:SetCollisionGroup( 15 )
		canEnt:Spawn()
		
		local phys = canEnt:GetPhysicsObject()
		if IsValid(phys) then
			phys:SetVelocity(self.Owner:GetForward() * 500)
		end
		
		timer.Simple(60, function() if IsValid(canEnt) then canEnt:Remove() end end)
		
		local oldModel = self.Owner:GetModel()
		self.Owner:SetModel("models/player/police.mdl")

		timer.Simple(1.5, function() if IsValid(self.Owner) then self.Owner:SetModel(oldModel) end end)

	end
	
	self.Owner.cantCan = true
	timer.Simple(3, function() if self.Owner:Alive() and !self.Owner:IsSpec() then self.Owner.cantCan = nil end end)

	self.Weapon:EmitSound( "npc/metropolice/vo/pickupthecan" .. math.Round(math.random( 1, 3 )) .. ".wav" )

end


Yes, I also tried a self.owner:IsValid() check but it didn’t work either.

You forgot to check if the owner is valid in this timer. Also you should always use IsValid(ent) and not ent:IsValid() to test if an entity exists/isvalid. Because if it does not exist you can not call a function from it.

If you still get errors try to split the function in the timer into multiple lines so you get a more detailed error location.

So now this error pops up…



[ERROR] gamemodes/terrortown/entities/weapons/weapon_ttt_stunbaton.lua:284: Tried to use a NULL entity!
  1. __index - [C]:-1
   2. unknown - gamemodes/terrortown/entities/weapons/weapon_ttt_stunbaton.lua:284

Timer Failed! [Simple][@gamemodes/terrortown/entities/weapons/weapon_ttt_stunbaton.lua (line 283)]


With this code…



	timer.Simple(3, function()      -- This is line 283
		if IsValid(self.Owner) then
			if self.Owner:Alive() then
				if self.Owner:IsSpec() then
					self.Owner.cantCan = nil
				end
			end
		end
	end)


By the way, this only happens when someone does the right click function, and then dies before the timer is done.

Is there anyway to set it up so that when the player dies, the timer gets removed?

Try to do:
[lua]
if IsValid(self) and IsValid(self.Owner) then

end
[/lua]

This will first check if the ent is valid and then if the owner is valid.

This actually stops the error from popping up, but it still stops the sound from playing and the spawning of cans when they respawn the next round.

I found a solution for the sound, I just put this in Initialize…



function SWEP:Initialize()
	self.Owner.cantCan = nil
end


The can still doesn’t spawn though. :frowning:

Bump

I am not a 100% sure what your problem is. Does the can not spawn at all? Or doesn’t it spawn after a player has repspawned and uses this weapon again?

When a player dies while the timer still runs, it’ll produce an (invisible) error. Setting the variable to true in SWEP:Initialize will make the sound play when they respawn in a new round, however it will not produce the can entity.