Only activate once in SWEP:Reload

Currently, I have a swep that is supposed to toggle a value every time the reload key is pressed. Here’s the code;
[lua]
function SWEP:Reload()
local response = {[true] = “enabled”, [false] = “disabled”}
local current = self.Weapon:GetNWBool( “temp_props”, false )
self.Weapon:SetNWBool( “temp_props”, not current )
self.Owner:PrintMessage(3, "Temporary props " … response[not current])
end
[/lua]
However, it runs every tick while the reload key is held down. I want it only to run once after it’s pressed until the key is released again. How would I go about doing that?
This seems like a really trivial problem that I’m having a surprisingly difficult time solving.

Reload is a predicted hook so you can cut down on some of the calls by checking if this is the first time the hook is being called per tick with

Global.IsFirstTimePredicted

From there I would go about this by setting a flag in the SWEP:Reload hook and then in the Think hook un-set the flag if the player isn’t holding IN_RELOAD with the

Player:KeyDown function.



function SWEP:Reload()
    if (IsFirstTimePredicted() and not self.Reloading) then
        self.Reloading = true
        -- Toggle your value
    end
end

function SWEP:Think()
    if (self.Reloading and IsValid(self.Owner) and not self.Owner:KeyDown(IN_RELOAD) ) then
        self.Reloading = false
    end
end


That seems somewhat inefficient, but I’ll try it. There isn’t a better way, like a hook I can listen to which is only called once?

I ended up using this code, which works pretty well;
[lua]
function SWEP:Reload()
if SERVER and IsFirstTimePredicted() then
if timer.Exists( “reload_stop_timer” ) then
timer.Adjust( “reload_stop_timer”, 0.01, 1, function() end )
return
else
timer.Create( “reload_stop_timer”, 0.01, 1, function() end )
end
local response = {[true] = “enabled”, [false] = “disabled”}
local current = self.Weapon:GetNWBool( “temp_props”, false )
self.Weapon:SetNWBool( “temp_props”, not current )
self.Owner:PrintMessage(3, "Temporary props " … response[not current])
end
end
[/lua]
It uses timers instead of hooking into SWEP:Think.

You should really take the suggestion and use Think instead of timers, they don’t do you any good in case of entity removal.

I’m not worried about entity removal. What do you mean? The timer will just end on it’s own if the weapon is removed during it’s execution.

Why do you think that, you dont pass the ent towards and whats wrong with Think? Thats how you should do it really.

EDIT: I see what you did there now but thats actually the hacky way which you wanted to avoid :v

I never said I wanted to avoid a “hacky way” as you describe it. I just wanted to do it efficiently without calling GM:Think. And this satisfies that.

IIRC, hooking on to think is more efficient than timers.

But ideally the reload button will only be pressed for a fraction of a second every couple minutes. Even if it were somewhat less efficient while it were being held down, it would be much more efficient than using GM:Think while it’s not held.

Why do you believe the Think hook is less efficient? Its not, and now that timers are done in C they are probably slower also.

Think is called every tick; you should therefore avoid putting code in it at all costs. If I put this simple check inside Think, it would be evaluated every single tick for every single player. Using my system though, no code is run related to the weapon except while the reload button is being held. Even if using timers is 10 times slower, even 100 times, it would still be more efficient since the code is never run all the time.

You are just being paranoid about placing code in Think, its not gonna be a bottleneck.

I’m not saying it’s a bottleneck here. But it’s good practice to avoid Think. If everyone, including me, put little bits of code in Think, then over a large number of scripts all of it would add up and lag out your game. I’m trying not to be a part of that problem.

The code I posted doesn’t add much overhead to the Think hook. The only thing that’s being evaluated when not holding down +reload is if self.Reloading is set, if it isn’t it ends there. That adds even less overhead than adjusting a timer every Reload call. Also your timer system won’t work correctly with multiple players using the swep as ‘reload_stop_timer’ isn’t a unique string id. And even if you do change the timer id to a unique id per weapon that will add more overhead to the timer system as the timer system is just a think hook and a queue system. Every tick the timer system just goes over its table of timers and checks if their next activation time is greater or equal to the current time, if so it activates. So if you add 1 unique timer per weapon your adding an extra if (CurTime() >= timer.NextFireTime) to the timers think system.

I don’t need a unique timer id; players would rarely ever press the button at the same time, and even then the only thing that would do is prevent one of them from not being able to switch back until another lets go. And making the timers unique isn’t much trouble anyway. And as I described above, yes; the overhead is negligible using Think, but it is also constant, and it adds up.

When timers were in Lua, they were checked every tick. I do not know if that changed when they moved to C++.

Look at it this way; would you rather play a game at 48 fps constantly, or play it at 60 the large majority of the time with occasional drops down to 30 for less than a second?

I’m not in any way implying my script has this kind of impact; I’m just using it as an analogy.

Then I will make the ids unique. Did you even read my post?