Forum

> > CS2D > Scripts > [✓] Is it possible to create a function for hooks?
Forums overviewCS2D overview Scripts overviewLog in to reply

English [✓] Is it possible to create a function for hooks?

20 replies
Page
To the start Previous 1 2 Next To the start

old [✓] Is it possible to create a function for hooks?

Nekomata
User Off Offline

Quote
Solved! Check http://www.unrealsoftware.de/forum_posts.php?post=419447&start=0#post419479

--------------------------------


So I'm trying to create a function within an OOP class to use for a addhook.

1
2
3
4
5
6
7
8
9
10
11
function Hook:Create(hookName, args, ...)
	self.hooks[hookName] = true
	self.hookCallable[hookName] = {
		args = args,
		__callableName = '____'..hookName
	}

	loadstring('self.hookCallable['..hookName..'].__callableName = function ('..args..') end')

	addhook(hookName, 'Hook.hookCallable["'..hookName..'"].__callableName')
end

This isn't working. Is there any way to create a function and use it for addhook within a method?

I've also tried this approach
1
loadstring('function ____'..hookName..'('..args..') end')
but it seems it's only being defined as a closure.

AFAIK, it does create the function and append it to the addhook but the addhook doesn't read the arguments, which is infact a STRING so it works with loadstring.
1
hook:Create('join', 'id')

And so, whenever someone joins, triggering the join hook, the cs2d addhook returns the error that the parameters are nil. How to do this?
edited 2×, last 20.02.18 05:48:48 pm

old Re: [✓] Is it possible to create a function for hooks?

Nekomata
User Off Offline

Quote
@user VADemon: OOP is the approach I'm taking because I'm making a little API.

Basically, this is how you initialize a hook in CS2D.
1
2
3
addhook("join", "_join")
function _join(id) -- Parameter taken
end

Which will boil down to
hook:Create('join', 'id')
.

Prototype
:Create(arg1, arg2)

Now what :Create() will do is make a function called ____arg1(arg2) and then addhook(arg1, "____"..arg1")

I need to know if there's a possible way to create a global function and have addhook use it successfully.

old Re: [✓] Is it possible to create a function for hooks?

DC
Admin Off Offline

Quote
One very important general problem (which was not documented properly, sorry):
cs2d lua cmd addhook does not resolve the [] stuff. The function you specifiy as string parameter must have the form "x.y.z" and no other stuff. [] is not required however:

foo['bar'] = 5
is the same as
foo.bar = 5
. But attention:
foo[bar]
is different because it will use the VALUE of the variable bar and not the string 'bar'.

So instead of
1
addhook(hookName, 'Hook.hookCallable["'..hookName..'"].__callableName')
it should rather be
1
addhook(hookName, 'Hook.hookCallable.'..hookName..'.__callableName')

Also your loadstring call is missing quotes around the hookName. Should be:
1
loadstring('self.hookCallable["'..hookName..'"].__callableName = function ('..args..') end')
or also just:
1
loadstring('self.hookCallable.'..hookName..'.__callableName = function ('..args..') end')

BUT Lua will maybe EXECUTE args at that point and just put its result there. This is not what you want. Or does it only do that when you put a () behind it? Not sure if you can / have to cast it to a string in some way.

So for debugging you should try if that loadstring approach actually worked by manually calling the method you created.

Possible solution for that args stuff: I don't think you need loadstring at all. Try this instead:
1
self.hookCallable[hookName].__callableName = args
If args is a function/closure thingy it should work that way and it should also be faster. Converting stuff to a string and letting Lua parse it again is kind of stupid.

When you made all that work it should not be necessary anymore to store args and __callableName. Just put the function directly in Hook.hookCallable[hookname] and don't store the rest.
1
self.hookCallable[hookName] = args
and
addhook(hookName, 'Hook.hookCallable.'..hookName)


I didn't test any of this and I'm rather sure that I missed something.
edited 4×, last 18.02.18 12:03:15 pm

old Re: [✓] Is it possible to create a function for hooks?

Nekomata
User Off Offline

Quote
Thanks for the elaborate response @user DC.

What I'm basically trying to do is make this:
1
2
addhook("join", "_join")
function _join(id) end

Into this:
1
2
local hook = Hook.new()
hook:Create("join", "id")

I've tried what you've suggested and like before I keep ending up with this in the console.

1
2
3
4
5
6
7
8
9
10
11
12
----- Server started -----
Lua: Adding function 'self.hookCallable.join' to hook 'join'




----Adding Bot----
LUA ERROR: attempt to index a nil value
U.S.G.N.: Serverlist entry updated
----I join here----
Player is using IP 192.168.100.6:60002 and no U.S.G.N. ID
PANIC: unprotected error in call to Lua API (attempt to index a nil value)

args, being the argument/parameters, was being passed as a string so I could register it as a function, like this:
function _join(id) end

hence,
function self.hookCallable[hookName](args) end


What I'm deriving from the PANIC: unprotected error in call to Lua API (attempt to index a nil value) error is that the hook is being registered successfully, but since it has no parameters set, whatever value comes down through it, such as the first parameters in the join hook would be user ID, it will be considered as nil.

I'm trying to get around that without having to register a global variable to store these functions since I'm taking the OOP approach. I hope this can be done?


Edit: Here's the OOP file: https://gist.github.com/irfan-dahir/9404a96d24c2c52ed2b496f835b4857e

Useable by adding this to server.lua
1
2
local hook = Hook:New()
hook:Create('join', 'id')

I went ahead and made changes and followed your instructions. But still ending up at the same place.

old Re: [✓] Is it possible to create a function for hooks?

DC
Admin Off Offline

Quote
I see two problems in the version you have in github:

• You're storing the functions in self.hooks.hookName but you're using addhook with self.hookCallable.hookName

• You're using "self" in addhook. That won't work. All tables/variables passed to addhook must be global tables because CS2D will do the lookup when the hook is actually being called. And at that time there won't be a "self" (unless you also declare it as a global table which certainly is a bad idea)

btw: "LUA ERROR: attempt to index a nil value" (if not caused by any other problem in scripts) probably indicates that CS2D can't find the table you specified in addhook (in that case the "self")

old Re: [✓] Is it possible to create a function for hooks?

Nekomata
User Off Offline

Quote
@user DC, I've gone ahead and corrected that. I was hoping I could have addhook() load the function from an OOP class, but that isn't possible it seems (afaik).

I've gone ahead and made a table out of the class for the callables that can hold the hook functions.

Updated Gist here: https://gist.github.com/irfan-dahir/9404a96d24c2c52ed2b496f835b4857e

But I still seem to be getting this error
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
----- Server started -----
Lua: Adding function 'HookCallable.join' to hook 'join'




----Adding Bot----
LUA ERROR: attempt to call a nil value
 -> [C]: in function 'parse'
 -> sys/lua/server.lua:6: in main chunk
 -> in Lua hook 'join', params: 1
LUA ERROR: attempt to call a nil value
 -> [C]: in function 'parse'
 -> sys/lua/server.lua:6: in main chunk
LUA ERROR (ai_onspawn)
Freezing bots to stop Lua error msg flood! Use 'bot_freeze 0' to unfreeze bots!
U.S.G.N.: Serverlist entry updated

-- I join here
Player is using IP 192.168.100.6:64332 and no U.S.G.N. ID
LUA ERROR: attempt to call a nil value
 -> in Lua hook 'join', params: 2
Any ideas?

This is on line 6 of the regarding error.
1
2
print('\n\n\n\n----Adding Bot----')
parse('bot_add_ct') -- line 6

BTW, thanks for the help so far!

old Yay!

Nekomata
User Off Offline

Quote
@user TrialAndError: A hook function needs parameters to operate. The join hook requires an id parameter. You've to set that.


On another note. I've managed to do it and it's working!
This is probably the epitome of the most dynamic way of managing Hooks.

Behold: https://gist.github.com/irfan-dahir/9404a96d24c2c52ed2b496f835b4857e

@user DC: I found a 'workaround' for passing the arguments.

1
loadstring('HookCallable.'..hookName..' = function('..args..') print(id) end')(...)


Now, since this requires both a string of the arguments and the arguments being passed. The method gets a little messy. This is how you define it.
1
hook:Create('join', 'id', id)

For hooks with more parameters, it gets a bit ugly.
1
hook:Create('die', 'victim, killer, wep, x, y, kObjID', victim, killer, wep, x, y, kObjID)

It has to be this way since there's no way of getting the name of the variables to make the function and passing them to the function dynamically.
If there is then we can get rid of that ugliness.

old Re: [✓] Is it possible to create a function for hooks?

TrialAndError
User Off Offline

Quote
I was wondering about the content of the function

1
2
3
4
loadstring('HookCallable.'..hookName..' = 
function('..args..')
	print(victim) -- This part
end')(...)

Will it need to be manually changed depending on the hook or will you have predefined definitions?

old Re: [✓] Is it possible to create a function for hooks?

Nekomata
User Off Offline

Quote
@user TrialAndError: Yes it has to! I'm planning on adding further 'event'-like callables. That final line will probably look something like this:


1
2
3
4
loadstring('HookCallable.'..hookName..' = 
function('..args..')
     self.Event(args) -- a loop executing all the callables for this hook
end')(...)

And there'd be an 'addEvent' method which takes care of that by adding callables to an array for that hook.
e.g
Hook:addEvent(hookname, functionCallable)


Ofcourse, you'll have to use the exact variable names you pass on to `Hook:Create`.

Haven't got there yet.
edited 1×, last 20.02.18 06:13:53 pm

old Re: [✓] Is it possible to create a function for hooks?

TrialAndError
User Off Offline

Quote
Don't use this solution.

Just a tip.
You could do this, to stop the repeat you'd want to use a split function to get the string into a table and unpack it when running the loadstring.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function string:split(m)
	local tbl = {} 
	for w in self:gmatch("[^" .. (m or "%s") .. "]+") do
		table.insert(tbl, w) 
	end 
	return tbl 
end

function Hook:Create(hookName, args)
	loadstring('HookCallable.'..hookName..' = function('..args..') print(victim, killer) end')(unpack(args:split(",")))
	addhook(hookName, "HookCallable."..hookName)
end

Hook:Create('die', 'victim, killer, wep, x, y, kObjID')
edited 1×, last 20.02.18 07:01:57 pm

old Re: [✓] Is it possible to create a function for hooks?

TrialAndError
User Off Offline

Quote
Wow, you don't even need to fill the parameters to the loadstring (as it's only running the code inside, and besides, what would the parameters even do), I feel dumb. So, you don't need any extra stuffs other than args for the function itself. In other words

1
2
3
4
5
6
function Hook:Create(hookName, args)
     loadstring('HookCallable.'..hookName..' = function('..args..') print(victim, killer) end')()
     addhook(hookName, "HookCallable."..hookName)
end

Hook:Create('die', 'victim, killer, wep, x, y, kObjID')

works the same.

old Re: [✓] Is it possible to create a function for hooks?

Yates
Reviewer Off Offline

Quote
I experienced issues with returning values and getting hooks to work properly when you want to use multiple for different functions and prioritise them. If you have any issues; you can check out my solution here.

You should also think about creating your own function to call when you want to create a custom hook that happens at a certain time within functions and possibly other hooks.

Just a thought.

old Re: [✓] Is it possible to create a function for hooks?

script favor
User Off Offline

Quote
Like this ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
MyClassName = {}
MyClassName.__index = MyClassName
MyClassName.__type = "MyClassName"

function MyClassName:new(constructor, arguments, etc, ...)
     
     local self = {}
     
     self.Value = constructor
     
     return setmetatable(self, MyClassName)
end

function MyClassName:__tostring() -- This is a metamethod
     
     return tostring( self.Value )
     
end

function MyClassName:__concat(what) -- This is a metamethod
     
     return tostring( self ) .. tostring( what )
     
end

function MyClassName:DoSomething() -- This is a method

end

function MyClassName:GetSomeValue() -- This is a method
     
     return self.Value
     
end

function MyClassName:SetSomeValue(Value) -- This is a method
     
     self.Value = Value
     
end
To the start Previous 1 2 Next To the start
Log in to reply Scripts overviewCS2D overviewForums overview