-
Notifications
You must be signed in to change notification settings - Fork 809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Listen-Only Hooks #2119
base: master
Are you sure you want to change the base?
Conversation
Thats a really great addition, but I guess it may conflict with some libraries with priorities, like ULX' hooks or others and break some functionality of some addons. |
The only problem I see is it conflicting with addons that completely override hook.Call |
Hi everyone. I want to express a problem here, and a potential solution to said problem. The problem has to do with post listen-only hooks. I added this feature so that, for example, someone could hook onto EntityEmitSound without having to worry about a hook returning true, but wouldn't want their hook to be called if false was returned. The problem here is that post-listen hooks are not called if a normal hook returned a value. So taking the same example there, it wouldn't matter what was returned (true or false) the hook wouldn't be called. This is not ideal. So I propose a solution that I want your feedback on. I hope these "examples" explain it well. -- The "rets" argument is a table that contains all of the values returned from the normal hook that returned a value (or values).
-- It is added as the first argument to every listen-only hook function. If the identifier for the hook is an object, "rets" will be the second argument instead.
-- The values in the table are reset right before each listen-only hook call, in-case that one of them messes with the table.
hook.Listen('EntityEmitSound', 'test', function(rets, data)
if rets[1] == false then return end -- Normal hook returned false prior, don't do anything
-- Do something with the sound. Sound alert system perhaps?
end) -- Outside entity
hook.Listen('EntityEmitSound', ent, function(self, rets, data)
if rets[1] == false then return end
-- do stuff
end)
----------------------------------
-- Inside entity
function ENT:Initialize()
hook.Listen('EntityEmitSound', self, self.OnEmitSound)
end
function ENT:OnEmitSound(rets, data)
if rets[1] == false then return end
-- do stuff
end Not only would this solve the problem, it would remove the need to have pre and post listen hooks. We can just have them all called after the normal hooks. I am looking forward to feedback on this, and whether or not I should update the PR with this. To me, this looks really weird, lol. Let me know what you think. |
I think this is a good idea, it allows modders to use the data returned by other hooks. Although, I do think that pre and post hooks should be implemented in the engine in general, but this is a good compromise. I do wonder what robotboy's opinion on adding this is? |
This pull request wants to add these 3 functions:
hook.Listen( string eventName, any name, bool isPostHook, function func )
hook.Forget( string eventName, any name, bool isPostHook )
hook.GetListenTable()
There is also a few micro-optimizations done to
hook.Add
andhook.Remove
with their type checking.Listen-only hooks are hooks that will call regardless if one had returned a value. These hooks will allow us to hook onto events without having to worry about a hook being ran before ours, returning a value, and completely skipping our logic, or about weird addons returning values when they shouldn't.
Example:
Let's say I wanted to have an effect happen every time I take a step. We use the PlayerFootstep event, and for this example, I made it create small puff balls of smoke at the position of every footstep you take. However, addons can return true to suppress the step sound, and unfortunately for us, the order in which hooks are called in is random. That means such hooks by those addons could run before ours, completely blocking our fancy little effect. Instead, we can use
hook.Listen
like so:That way, even if an addon returns a value in their hook, we still have our fancy smoke effect on each step.
Setting the third argument to true will make the listen-only hook be called after all of the normal hooks are called. This can be used to make sure your logic is only called if a hook return didn't happen. For example, let's say I wanted to track how many times the player toggled their flashlight. I can do this like so
Addons can block us from toggling our flashlight by returning false. That mean's there is a chance our logic is completely skipped. So, we use
hook.Listen
. However, listen-only hooks are called before normal hooks, so there's a chance we add onto that variable, even if the toggle was blocked or not. So, by setting the third argument to true, we can make that listen-only hook be called after the rest, that way we can make sure we are counting unblocked flashlight changes, with no worry of our logic being randomly skipped.Listen and post listen hooks are put in two separate tables. Listen only hooks can also have objects as identifiers, just like regular hooks.
You can remove listen-only hooks like so:
You can get the listen-only hook tables like so:
I am awaiting feedback.