#
reflection
Responsible for lua-scripting execution and handling of API access cross-states.
You can use this to also contact other lua_State instances, and create new ones.
Do note you are responsible for spinning up new states.
lua_State Data Transfer
Data transfer for these types are prohibited due to complications & safety:
- Thread
- Proto (this is being worked on)
#
Threading
As of currently, the thread isolation for lua_State is quite basic.
As an example, if we create a new lua_State with thread isolation:
local diff = os.clock()
local schedule_response = false
-- this section runs under its own thread thanks to task.*
task.add("test", function()
if diff + 1 < os.clock() then
diff = os.clock()
if schedule_response then
signal.fire(reflection.get("server"), "test", schedule_response)
schedule_response = false
end
end
end)
-- this section when executed will be in-sync with which ever thread/lua_State called it.
-- therefore **this is not actually threaded here**.
-- so I recommend task deferring into task.* think operation above.
signal.add("test", "incoming", function(...)
print("from main thread:", ...)
signal.fire(reflection.get("server"), "test", "got data!")
schedule_response = "hello world"
end)
Nothing is perfect here, so do expect some problems with this system.
Currently task.* only supports "think" operation, which runs every possible cycle.
Do note that some cfunctions may not work depending on how they are implemented.
#
Functions
reflection.is(name: string): boolean
- Checks if the current execution is of a named
lua_State
reflection.get(name: string): lua_State?
- Attempts to locate a
lua_State
reflection.current(): lua_State
- Gets the current
lua_State
this is executed in
reflection.all(): {[index: string]: lua_State}
- Gets all instances of
lua_State
and their names
reflection.execute(source: string, name: string, state?: lua_State): string?
- Executes lua on a
lua_State
or the current active state its in
reflection.compile(source: string, name: string): function | string
- Compiles lua on the the current active state its in
reflection.open(name: string, threaded: boolean): lua_State
- Spawns a new
lua_State
instance or returns one if it already exists - By enabling threaded, will open the lua_State with its own runtime environment.
- This can be accessed via
task.*
which is a signal specific for that state.
-- creates a new lua_State
local state = reflection.open("lua_State.magic")
-- execute lua right onto the stack
reflection.execute([[
print("new lua_State boys!")
]], "test", state)
-- you can use basic stack manipulation here as well
print("\nprinting this lua_State's stuff")
reflection.stack(function(L)
L:pushvalue(-10002)
L:pushnil()
while L:next(-2) do
if L:isstring(-2) then
print(L:getstring(-2))
end
L:pop()
end
end, state)
-- if you really don't need it, you can close it
reflection.close(state)
reflection.close(state: lua_State)
- Destroys a
lua_State
instance - This won't work on games with built-in
lua_State
instances
reflection.stack(func: function(L: lua_State), state?: lua_State): any...
- Creates a stack isolated bridge to a lua_State.
- Do note that you don't need to do this but using this reduces the risk of overflows.
-- this is in menu-state or another lua-state
local other_state = reflection.get("other_state")
local res = reflection.stack(function(L)
L:pushnumber(20)
local num = L:tonumber(-1)
L:pop()
return num
end, other_state)
print(res) -- 20
-- you can also do it outside the stack isolation if needed:
L:pushnumber(20)
local res = L:tonumber(-1)
L:pop()
print(res) -- 20
#
Events
Events that can be accessed under reflection.listener
open(name: string, state: lua.state)
- Called when a lua_State has been created.
- Do note that during the event, lua_State has not been fully initialized.
- This can result in undefined behavior due to invalid objects, such as no _G being available.
- We recommend you defer a task before running anything.
close(name: string, state: lua.state)
- Called just before a lua_State is destroyed.
- Typically managed by C itself on when a lua_State should be destroyed.
#
Lua State
These are interface & function definitions for how we handle lua_State
Non-Preemptive Errors
This library can cause internal errors in Lua, likely causing a crash.
We are working on isolating this better to prevent Lua itself from invoking exits.
L:execute(source: string, name: string): string?
- executes lua on a
lua_State
.
L:compile(source: string, name: string): string?
- Compiles lua on a
lua_State
. - Do note that doing this will push the function onto the stack, consider seeing more in CAPI.
L:stack(func: function(L: lua_State)): any?
- Creates a stack isolated bridge to a lua_State.
- Do note that you don't need to do this but using this reduces the risk of overflows.
L:name(): string
- Converts a
lua_State
to its named counterpart
L:threaded(): boolean
- Checks if the
lua_State
is running under a threaded environment
L:internal(): boolean
- Checks if the
lua_State
is internally created - Internals prevent certain actions from being made, such as destruction
L:root(): boolean
- Checks if the
lua_State
is a root of all otherlua_State
under it
L:parent(): lua_State?
- Gets the parented
lua_State
L:children(): lua_State[]
- Gets all children associated with the
lua_State
L:api(): API
- Pushes the API onto the stack for access
L:call(inputs: number, outputs: number)
- Calls a function thats pushed onto the stack
- This will consume the no. inputs first, then execute the functions
L:compile("print(({...})[1])", "example")
L:pushstring("hello world")
L:call(1, 0) -- calls "example" with "hello world"
L:pop(count?: number)
- Pops a value off of the stack at the top
L:remove(index: number)
- Removes a value at an index off of the stack
L:length(index: number): number
- Used to get the length of a value
L:next(index: number): boolean
- A pair-style iterator function for going through table
L:newtable() -- example
L:pushnil() -- push an invalid key to jump-start the iterator
while L:next(-2) do -- target table for key-grabbing
-- this pushes 2 values onto the stack, -1: value, -2: key
L:pop(); -- pop the value, keep the key so 'next' can keep going
end
L:pop() -- pop table off stack
L:pushany(value: any)
- Transfers any datatype from your environment to the stack
L:getany(index: number): any
- Transfers any datatype from the stack to your environment
L:gettop(): number
- Gets the current size of the Lua stack
- This is useful for vararg style handling
L:gettype(index: number): number
- Gets the type ID of a given value
L:gettypename(index: number): string
- Gets the typename of a given value
L:newtable()
- Generates a blank table and pushes it onto the stack
L:newref(index: number): number
- Creates a reference link to a value
- This will make the value immune to the garbage collector
L:pushref(reference: number)
- Pushes the referenced value back onto the stack
L:rmref(reference: number)
- Removes the referenced value from registry
L:getupvalue(index: number, id: number): string
- Gets the "upvalue" of a function at the top of the stack
- Upvalues are values passed to a function not as a parameter, but by reference
L:setupvalue(index: number, id: number): string
- Sets the "upvalue" of a function at the top of the stack
L:getfenv(index: number)
- Grabs the ENV and pushes it onto the stack
- You can use this to manipulate the environment
L:setfenv(index: number)
- Sets the ENV of a functions at the index
- This consumes the table you provide it at the top of the stack
- You can use this to manipulate the environment
L:getmetatable(index: number): boolean
- Grabs the metatable of a table or userdata, and pushes it onto the stack
- The boolean is provided for if it fails to grab the metatable
L:setmetatable(index: number)
- Sets the metatable of a table or userdata at the index
- This consumes the table you provide it at the top of the stack
L:getfield(index: number, key: string)
- Gets the value from a table and pushes it onto the stack
L:setfield(index: number, key: string)
- Sets a value in a table by key
- Index corresponds to where the table is on the stack
L:gettable(index: number)
- Gets the value from a table and pushes it onto the stack
- This will consume a value just before it to determine the key
L:settable(index: number)
- Sets a value in a table by the key at the top of the stack
- The top of the stack is the key, and top-1 is the value
L:rawget(index: number)
- Gets the value from a table and pushes it onto the stack
- This will consume a value just before it to determine the key
- Unlike gettable this will not invoke metatable callbacks
L:rawset(index: number)
- Sets a value in a table by the key at the top of the stack
- The top of the stack is the key, and top-1 is the value
- Unlike settable this will not invoke metatable callbacks
L:getboolean(index: number): boolean
- Attempts to get a boolean value from the Lua stack
- If the type is invalid, an error will be thrown
L:getnumber(index: number)
- Attempts to get a number value from the Lua stack
- If the type is invalid, an error will be thrown
L:getstring(index: number)
- Attempts to get a string value from the Lua stack
- If the type is invalid, an error will be thrown
L:pushboolean(value: boolean)
- Pushes a boolean onto the stack
L:pushnil()
- Pushes a nil value onto the stack
L:pushnumber(value: number)
- Pushes a number onto the stack
L:pushstring(value: string)
- Pushes a string onto the stack
L:pushfunction(value: function)
- Pushes a function onto the stack
L:pushtable(value: table)
- Pushes a table onto the stack
L:pushvalue(index: number)
- Makes a copy of a value at the index and pushes it to the top of the stack
L:isboolean(index: number): boolean
- Checks if the value at index on the stack is a boolean
L:iscfunction(index: number): boolean
- Checks if the value at index on the stack is a cfunction
L:isfunction(index: number): boolean
- Checks if the value at index on the stack is a function
L:islightuserdata(index: number): boolean
- Checks if the value at index on the stack is a lightuserdata
L:isnil(index: number): boolean
- Checks if the value at index on the stack is nil
L:isnumber(index: number): boolean
- Checks if the value at index on the stack is a number
L:isstring(index: number): boolean
- Checks if the value at index on the stack is a string
L:istable(index: number): boolean
- Checks if the value at index on the stack is a table
L:isthread(index: number): boolean
- Checks if the value at index on the stack is a thread
L:isuserdata(index: number): boolean
- Checks if the value at index on the stack is a userdata
L:istype(index: number, type: number): boolean
- Checks if the value matches a specific type ID