A function binding function.
[lua]function BindFunction(func, object, ...)
local args = {...}
return function(...)
return func(object, unpack(table.Add(table.Copy(args), {...})))
end
end[/lua]
[QUOTE=sannys;51898628]A function binding function.
[lua]function BindFunction(func, object, ...)
local args = {...}
return function(...)
table.Add(args, {...})
return func(object, unpack(args))
end
end[/lua][/QUOTE]
What kind of use is there for this?
[QUOTE=txike;51898762]What kind of use is there for this?[/QUOTE]
Imagine you have an object with a function defined with the [B]:[/B] character
[lua]local Person = {Name = "Garry"}
function Person:Greet()
print("My name is", self.Name)
end
Person:Greet()[/lua]
That's completely fine. But what if you wanted to save that Greet function into a variable, and then call that variable?
[lua]local Person = {Name = "Garry"}
function Person:Greet()
print("My name is", self.Name)
end
local greet = Person.Greet
greet()[/lua]
This code would generate an error because you cannot implicitly include a self reference like that.
[quote]attempt to index local 'self' (a nil value)[/quote]
In order to make that code work, you'd have to pass the self reference manually (or manually wrap it in a function).
[lua]greet(Person)[/lua]
However, if we make a bind for it, we don't need to do that anymore.
[lua]local greet = BindFunction(Person.Greet, Person)
greet()[/lua]
Usually the first argument would be a metatable's method, and the second argument would be an instance of that class. Basically it just lets you not have to worry about self references when saving object methods to a variable.
[QUOTE=sannys;51898840]:snip:[/QUOTE]
if you're using BindFunction just to add in the `self` arg to a member function, why not go for a simple solution like
[CODE]
function bind(f,self) return function(...) return f(self,...) end end
bind(Person.Greet,Person)
[/CODE]
no idea why you're using table.Add in your original code: that would eventually result in `args` getting very large and all past args being passed into the bound function each time you call it
[QUOTE=swadicalrag;51898883]if you're using BindFunction just to add in the `self` arg to a member function, why not go for a simple solution like
[CODE]
function bind(f,self) return function(...) return f(self,...) end end
bind(Person.Greet,Person)
[/CODE]
no idea why you're using table.Add in your original code: that would eventually result in `args` getting very large and all past args being passed into the bound function each time you call it[/QUOTE]
It's not only for self references. It's used to prepend extra arguments.
[url]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind[/url]
I see what you mean with the args becoming increasingly large, though. This should do it.
[lua]function BindFunction(func, object, ...)
local args = {...}
return function(...)
return func(object, unpack(table.Add(table.Copy(args), {...})))
end
end[/lua]
[QUOTE=sannys;51898923]It's not only for self references. It's used to prepend extra arguments.
[url]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind[/url]
I see what you mean with the args becoming increasingly large, though. This should do it.
[lua]function BindFunction(func, object, ...)
local args = {...}
return function(...)
return func(object, unpack(table.Add(table.Copy(args), {...})))
end
end[/lua][/QUOTE]
FWIW, object is now just one of the args unless it's nil, and in correct usage it would never be nil.
Speaking of nil, I think args can't end in nil, for example:
[lua]local Person = { name = "Bob" }
function Person:Greet(...)
print( self.name, ...)
end
local bf = BindFunction(Person.Greet, Person, nil)
bf("yay")
Person:Greet(nil, "yay")[/lua]
Admittedly haven't tested this, but I'm sure the first one skips the nil.
Edit: This can be solved by "hard-coding" the number of arguments from args into a RunString that generates the function you'll return. select("#", ...) will correctly handle nils as actual values. You also won't have to use table.Copy or table.Add at any point, so executing the function will be faster! However, generating it will be slower probably, since you'd be compiling a string.
I'm geeking out about this, I don't even think binding like this is useful. :happy:
you can use select("#",...) to get the length of a vararg and go from there
I wrote a quick [URL="https://gist.github.com/SwadicalRag/2ff9f46b1d9a182ebab2b23a84edb075"]vararg helper library[/URL], using that, you can rewrite BindFunction as:
[CODE]
local varg = (include or dofile)("varg.lua")
function BindFunction(fn,...)
local base = varg(...)
return function(...)
return fn(base + varg(...))
end
end
[/CODE]
[editline]3rd March 2017[/editline]
I made a typo, I meant
[CODE]
return fn((base + varg(...)):Unpack())
[/CODE]
(I can't edit my post for some reason :/)
Your library is pretty cool, but for what it's worth my method would run the bind without any overhead, whereas yours would concatenate the args and unpack them every time.
[QUOTE=sannys;51898923]It's not only for self references. It's used to prepend extra arguments.
[url]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind[/url]
I see what you mean with the args becoming increasingly large, though. This should do it.
[lua]function BindFunction(func, object, ...)
local args = {...}
return function(...)
return func(object, unpack(table.Add(table.Copy(args), {...})))
end
end[/lua][/QUOTE]
Why are you making a copy of args? It seems like it would breaking things in weird and wonderful ways.
[QUOTE=sannys;51898628]A function binding function.
[lua]function BindFunction(func, object, ...)
local args = {...}
return function(...)
return func(object, unpack(table.Add(table.Copy(args), {...})))
end
end[/lua][/QUOTE]
[DEL]or more simply put without the unnecessary table fuckery:[/DEL]
read below as to why this is wrong
[code]
function bind( func, ... )
local a = { ... }
return function( ... )
return func( unpack( a ), ... )
end
end
[/code]
[QUOTE=ZeBull;51902973]or more simply put without the unnecessary table fuckery:
[code]
function bind( func, ... )
local a = { ... }
return function( ... )
return func( unpack( a ), ... )
end
end
[/code][/QUOTE]
Unless the result list comes as the last expression in the argument list, then it will be adjusted to the first element only. So this will only pass the first element of `a`
apply damage on npc_helicopter
[lua]
aa("EntityFireBullets", function(client, data)
local oldCallback = data.Callback
data.Callback = function(client, trace, dmgInfo)
if (oldCallback) then
oldCallback(client, trace, dmgInfo)
end
if (trace) then
local target = trace.Entity
if (IsValid(target) and target:IsNPC()) then
if (target:GetClass() == "npc_helicopter") then
local dmg = DamageInfo()
dmg:SetDamage(data.Damage)
dmg:SetAttacker(client)
dmg:SetDamageType(DMG_AIRBOAT)
target:TakeDamageInfo(dmg)
target:SetNW2Int("health", target:Health())
end
end
end
end
return true
end)[/lua]
[QUOTE=rebel1324;51944400]apply damage on npc_helicopter
[lua]
aa("EntityFireBullets", function(client, data)
local oldCallback = data.Callback
data.Callback = function(client, trace, dmgInfo)
if (oldCallback) then
oldCallback(client, trace, dmgInfo)
end
if (trace) then
local target = trace.Entity
if (IsValid(target) and target:IsNPC()) then
if (target:GetClass() == "npc_helicopter") then
local dmg = DamageInfo()
dmg:SetDamage(data.Damage)
dmg:SetAttacker(client)
dmg:SetDamageType(DMG_AIRBOAT)
target:TakeDamageInfo(dmg)
target:SetNW2Int("health", target:Health())
end
end
end
end
return true
end)[/lua][/QUOTE]
Doesn't the helicopter already take damage though?
You can go try shooting bullets on helicopter now.
If you successfully take down the heli without any mods and rpg, I'll give you ferrari
[url]https://gist.github.com/meepdarknessmeep/a2bb9c61e2cca03e2a37b2d305b1e0e0[/url]
This loads a non-power-of-2 PNG into a Garry's Mod texture without flipping the fuck out. It's async so you could implement it with coroutine in mind.
It will be used in an upcoming release of mine.
Super duper simple table replace function... Is there already a function for this on the wiki? I made it cause I couldn't find one lol.
[CODE]local function tableReplace(Table, pos, value)
if (Table[pos]:IsValid()) then
table.remove(Table, pos)
table.insert(Table, pos, value)
else
table.insert(Table, pos, value)
end
end[/CODE]
[QUOTE=MrRalgoman;52087959]Super duper simple table replace function... Is there already a function for this on the wiki? I made it cause I couldn't find one lol.
[CODE]local function tableReplace(Table, pos, value)
if (Table[pos]:IsValid()) then
table.remove(Table, pos)
table.insert(Table, pos, value)
else
table.insert(Table, pos, value)
end
end[/CODE][/QUOTE]
[code]
table[pos] = value
[/code]
[QUOTE=MPan1;52087969][code]
table[pos] = value
[/code][/QUOTE]
Well hey, you learn something new everyday.
Useful for debugging (especially from console via lua_run[_cl]):
[lua]function Print(...)
if select("#", ...) == 1 and type(...) == "table" then
PrintTable(...)
else
print(...)
end
end[/lua]
Print(somevar) will use PrintTable if somevar is a table, and in all other cases, will use the regular print. I'm trying to make it good enough and test it enough to make a pull request, I think this is useful enough to be in vanilla gmod.
[QUOTE=NeatNit;52224652]Useful for debugging (especially from console via lua_run[_cl]):
[lua]function Print(...)
if select("#", ...) == 1 and type(...) == "table" then
PrintTable(...)
else
print(...)
end
end[/lua]
Print(somevar) will use PrintTable if somevar is a table, and in all other cases, will use the regular print. I'm trying to make it good enough and test it enough to make a pull request, I think this is useful enough to be in vanilla gmod.[/QUOTE]
this is so useful and simple yet i never thought about it lol
[QUOTE=NeatNit;52224652]Useful for debugging (especially from console via lua_run[_cl]):
:snip:
Print(somevar) will use PrintTable if somevar is a table, and in all other cases, will use the regular print. I'm trying to make it good enough and test it enough to make a pull request, I think this is useful enough to be in vanilla gmod.[/QUOTE]
You can get rid of the `select` call if you give it a first argument, i.e.
[code]
function Print(val, ...)
if ... == nil and type(val) == "table" then
PrintTable(val)
else
print(val, ...)
end
end
[/code]
Edit: Though this'd make it break if given nil as second argument, edge case failures wew
[QUOTE=bigdogmat;52224930]You can get rid of the `select` call if you give it a first argument, i.e.
[code]
function Print(val, ...)
if ... == nil and type(val) == "table" then
PrintTable(val)
else
print(val, ...)
end
end
[/code]
Edit: Though this'd make it break if given nil as second argument, edge case failures wew[/QUOTE]
It would also not allow no value for val, e.g. Print() would behave like print(nil) instead of print(). Varargs are tricky business.
If this is about performance, forget all about it. print, PrintTable and now Print are all debugging tools. As long as they don't significantly freeze the game (which they don't), there is no reason to optimize them.
Invert player movement through input without messing up ladder interaction
[lua]local CUserCmd = FindMetaTable( "CUserCmd" )
function CUserCmd:AddKey( keys )
local newbuttons = bit.bor( self:GetButtons(), keys )
self:SetButtons( newbuttons )
end
hook.Add( "CreateMove", "InvertPlayerMovement", function( cmd )
local fr, sd = cmd:GetForwardMove(), cmd:GetSideMove()
local frA, bkA, lfA, rtA
if cmd:KeyDown( IN_FORWARD ) then -- If the player is walking forward
cmd:RemoveKey( IN_FORWARD ) -- Make us think he's not going forward
cmd:SetForwardMove( -math.abs(fr) ) -- Make the player walk backwards
bkA = true -- We'll need to change the input later
end
-- Do the same for all other directions
if cmd:KeyDown( IN_BACK ) then
cmd:RemoveKey( IN_BACK )
cmd:SetForwardMove( math.abs(fr) )
frA = true
end
if cmd:KeyDown( IN_MOVERIGHT ) then
cmd:RemoveKey( IN_MOVERIGHT )
cmd:SetSideMove( -math.abs(sd) )
lfA = true
end
if cmd:KeyDown( IN_MOVELEFT ) then
cmd:RemoveKey( IN_MOVELEFT )
cmd:SetSideMove( math.abs(sd) )
rtA = true
end
-- Change the input
if bkA then cmd:AddKey( IN_BACK ) end
if frA then cmd:AddKey( IN_FORWARD ) end
if lfA then cmd:AddKey( IN_MOVELEFT ) end
if rtA then cmd:AddKey( IN_MOVERIGHT ) end
end )[/lua]
-snip, was wrong-
[QUOTE=code_gs;52231792]You're still setting the side and forward moves incorrectly. If someone holds front and back, they're going to move backwards because of how you ordered the speed calls.[/QUOTE]
Why would that be the case? GetForwardMove will return 0 and you won't move at all, as I store the value before messing with the input
[QUOTE=JasonMan34;52396726]Iterate through a string-indexed table in alphabetical order:
Compared to:
[/QUOTE]
[url]https://wiki.garrysmod.com/page/Global/SortedPairs[/url]
:)
I'm sure I've posted this before, but just in case I haven't, here's two things someone might find useful:
[URL="https://github.com/MysteryPancake/GMod-Rainbows"]A bunch of functions for drawing rainbow stuff[/URL]
[URL="https://github.com/MysteryPancake/GMod-Binding"]A module for binding keys and mouse and controller buttons to run stuff[/URL]
[url]https://gist.github.com/meepdarknessmeep/447587d427553c0277d9cb09d4199258[/url]
Something I made in 2015 to statically draw something and store the draw so it doesn't eat frames. Last time I tried it it saved me a ton of fps on even small drawing functions. I also tried it wrong (not making the function outside the hook). I've included the license and an example.
Sorry, you need to Log In to post a reply to this thread.