Skip to content

Instantly share code, notes, and snippets.

@ColonelThirtyTwo
Created September 1, 2013 22:26
Show Gist options
  • Save ColonelThirtyTwo/6407729 to your computer and use it in GitHub Desktop.
Save ColonelThirtyTwo/6407729 to your computer and use it in GitHub Desktop.
Library for calling E2 functions from Starfall. Hasn't been tested in awhile, and since it requires mocking the E2 entity, may not work with all functions.
-------------------------------------------------------------------------------
-- Expression 2 Foreign Functions Interface Library
-------------------------------------------------------------------------------
local functions_cache = setmetatable({},{__mode="v"})
local function identity(v) return v end
local lua2e2_converters = {
["number"] = identity,
["string"] = identity,
["boolean"] = function(v) return v and 1 or 0 end,
["Vector"] = function(v) return {v[1], v[2], v[3]} end,
["Angle"] = function(v) return {v[1], v[2], v[3]} end,
["table"] = function(v) return SF.Entities.Unwrap(v) end,
["nil"] = identity,
}
local e22lua_converters = {
["n"] = identity,
["s"] = identity,
["v"] = function(v) return Vector(v[1], v[2], v[3]) end,
["a"] = function(v) return Angle(v[1], v[2], v[3]) end,
["e"] = function(v) return SF.Entities.Unwrap(v) end,
}
local lua2e2_types = {
["number"] = "n",
["string"] = "s",
["boolean"] = "n",
["Vector"] = "v",
["Angle"] = "a",
["table"] = "e",
["nil"] = "e",
}
local container_metatable = {
__call = function(self) return self.val end,
}
SF.Libraries.AddHook("initialize", function(instance)
local fakecontext = {
data = {},
funcs = nil,
funcs_ret = nil,
entity = instance.data.entity,
player = instance.player,
uid = instance.player and instance.player:UniqueID(),
prf = 0,
prfcount = 0,
prfbench = 0,
includes = nil,
Scopes = {[0]={}},
ScopeID = 0,
}
fakecontext.Scope = fakecontext.Scopes[0]
fakecontext.GlobalScope = fakecontext.Scope
instance.data.e2ffi_fakeContext = fakecontext
wire_expression2_CallHook("construct", fakecontext)
end)
SF.Libraries.AddHook("deinitialize", function(instance)
if instance.data.e2ffi_fakeContext then
wire_expression2_CallHook("destruct", instance.data.e2ffi_fakeContext)
end
end)
--- Extension library that allows the use of certain E2 functions in Starfall.
-- Only the following types are supported: number, string, entity, vector, and angle.
-- true and false are converted to 1 and 0 respectively, and nil is a null entity. Any other
-- types will cause an error. Vararg functions are not supported.
-- Using the wrappers is somewhat expensive, so don't make heavy use of them.
local e2ffi_library, _ = SF.Libraries.Register("e2ffi")
--- Creates a wrapper function around an E2 function or method. This converts between E2 and SF types.
-- @param header The function definition string. This starts with the function name and an open
-- parenthesis, then zero or more 1 character E2 type strings ('n', 's', etc.), followed by a closing
-- parenthesis. Ex. 'holoPos(nv)'. Methods are formed like functions, but have a semicolon in the
-- type string. Ex. 'applyForce(e:v)'.
function e2ffi_library.getFunction(header)
if functions_cache[header] then return functions_cache[header] end
local funcdef = wire_expression2_funcs[header]
if not funcdef then error("No such E2 function: "..header,2) end
local e2function = funcdef[3]
local retconverter = e22lua_converters[funcdef[2]]
local funcname, typestr = string.match(header, "^(%l%a*)%((%l?:?%l*)%)$")
assert(funcname)
local types = {}
local fakefunc = {e2function}
for i=1,#typestr do
local e2type = typestr:sub(i,i)
if e2type ~= ":" then
if not e22lua_converters[e2type] then error("Incompatible E2 type: "..e2type, 2) end
local j = #types+1
types[j] = e2type
fakefunc[j+1] = {setmetatable({},container_metatable)}
end
end
local wrapped = function(...)
for i=1,#types do
local v = select(i,...)
local t = type(v)
if lua2e2_types[t] ~= types[i] then
error(string.format("Type mismatch for argument %n of e2function %s", i, header),2)
end
fakefunc[i+1][1].val = lua2e2_converters[t](v)
end
local v = e2function(SF.instance.data.e2ffi_fakeContext, fakefunc)
if retconverter then return retconverter(v) end
end
functions_cache[header] = wrapped
return wrapped
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment