8. Using Reflection

The Reflection System is a system that allows to get data about functions, classes, properties and structs.

It contains information about their structure, parameters of functions and other technical and structural data as well as metadata like descriptions and localized display names of the different things.

This data is heavily used internally and also can be accessed from within Lua code.

Reflection Data in Lua

The mentioned findClass function allows you to search for a class by its name. It returns an instance of a class containing information about it.

local class = findClass("NetworkCard")

This instance contains functions and properties that allow you to get information about the class it represents.
It extends from Struct, and it extends from ReflectionBase, the base type of all reflection data classes.
ReflectionBase:

  • name (property)
    The internal name of the data object as a string. f.e. the function name you use in Lua.

  • displayName (property)
    A display name with better and more human-readable text of the object.

  • description (property)
    A human-readable description explaining what the data object does.
    (f.e. functionality of the function, uses of the class)

The "Struct" Class provides functions and properties about a struct specifically. Like what properties and what functions the Struct it Represents has.
Check the Reference for more details.

The "Class" Class provides the finally additionally information about signals a instance of this class might emit. Check the Reference for more details.

Using Reflection Viewer and Reference

As Reflection Viewer we mean the "Reflection" Tab in the computer case UI or the network manager tool, that shows all available types, functions, etc.

As Reflection Reference we mean the Reflection page in this web documentation.

Both of these, list all the contents of the reflection system language independent.
That’s why you won’t find stuff like the component or event API in here, because this stuff is language (Lua) dependent.

The reflection viewer can show all data of class and its inherited functions etc. all on one page, the reflection reference can not.
You can disable this behaviour of the reflection viewer in the bottom right corner.

Let’s try to read the reflection data.

We want to first, read the Recipe of a Constructor and prints its name to the console, after that we want to get a signal whenever Item got outputted and print something.

At first, lets search for a constructor in the reflection data.
You won’t be able to find it in the online documentation, as it will unnecessarily bloat it, but you can find it in the in-game reflection viewer.

On the left you can see of which classes the constructor extends from.
On of these is the "Manufacturer" Class. Let’s have a look at it.
This time it is also available on the online documentation:

=== Manufacturer Manufacturer

Parent

The base class of every machine that uses a recipe to produce something automatically.

==== Functions

===== Get Recipe getRecipe (Class(Recipe) Recipe recipe out) Returns the currently set recipe of the manufacturer.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Recipe recipe

Class(Recipe) out

The currently set recipe.

===== Get Recipes getRecipes (Array(Class(Recipe)) Recipes recipes out) Returns the list of recipes this manufacturer can get set to and process.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Recipes recipes

Array(Class(Recipe)) out

The list of avalible recipes.

===== Set Recipe setRecipe (Class(Recipe) Recipe recipe, Bool Got Set gotSet out) Sets the currently producing recipe of this manufacturer.

Flags

RuntimeSync

Parameters
Name Type Description

Recipe recipe

Class(Recipe)

The recipe this manufacturer should produce.

Return Values
Name Type Description

Got Set gotSet

Bool out

True if the current recipe got successfully set to the new recipe.

===== Get Input Inventory getInputInv (Trace(Inventory) Inventory inventory out) Returns the input inventory of this manufacturer.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Inventory inventory

Trace(Inventory) out

The input inventory of this manufacturer

===== Get Output Inventory getOutputInv (Trace(Inventory) Inventory inventory out) Returns the output inventory of this manufacturer.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Inventory inventory

Trace(Inventory) out

The output inventory of this manufacturer.

Since we first want to get a recipe lets search for a function or property, that could do that.

===== Get Recipe getRecipe (Class(Recipe) Recipe recipe out) Returns the currently set recipe of the manufacturer.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Recipe recipe

Class(Recipe) out

The currently set recipe.

You can read a description and other information.
The flags "RuntimeSync" and "RuntimeParallel" show that we can only use the function in the non-promoted Lua tick state.
What that exactly means will be discussed in a later section.

The title consists of:
Display Name internalName (Parameter, List)
The display name is a human readable name of the function.
The internal name is used f.e. inside lua as function name.
The parameter list are all arguments and return values of the function.
Parameters with the out keyword are return values.
You can have multiple return values.

Parameters are further down described in the Parameter and Return Values section.

We can see that a instance of a manufacturer (which a instance of constructor is), has a member function getRecipe that returns a Class Instance of a Recipe.

local manufacturer = component.proxy(...)
local recipe = manufacturer:getRecipe()

You can click on the link of the parameter type to get redirected to the reference of that type.

=== Recipe Recipe

Parent

A struct that holds information about a recipe in its class. Means don’t use it as object, use it as class type!

==== Properties

===== String Name name The name of this recipe.

Flags

ClassProp RuntimeSync RuntimeParallel ReadOnly

===== Float Duration duration The duration how much time it takes to cycle the recipe once.

Flags

ClassProp RuntimeSync RuntimeParallel ReadOnly

==== Functions

===== Get Products getProducts (Array(Struct(ItemAmount)) Products products out) Returns a array of item amounts, this recipe returns (outputs) when the recipe is processed once.

Flags

ClassFunc RuntimeSync RuntimeParallel

Return Values
Name Type Description

Products products

Array(Struct(ItemAmount)) out

The products of this recipe.

===== Get Ingredients getIngredients (Array(Struct(ItemAmount)) Ingredients ingredients out) Returns a array of item amounts, this recipe needs (input) so the recipe can be processed.

Flags

ClassFunc RuntimeSync RuntimeParallel

Return Values
Name Type Description

Ingredients ingredients

Array(Struct(ItemAmount)) out

The ingredients of this recipe.

Here you can find a couple of functions and properties that have the ClassFunc or ClassProp flag.
This flag describes that it is available when you have a class instance of that type.

We want the name property as it gives us the name of the recipe.

print(recipe.name)

Now we want to figure out how we can get a signal when an item gets outputted.

Let’s search further one of the parents of our Manufacturer.

=== Actor Actor

Parent

This is the base class of all things that can exist within the world by them self.

==== Properties

===== Struct(Vector) Location location The location of the actor in the world.

Flags

RuntimeSync RuntimeParallel ReadOnly

===== Struct(Vector) Scale scale The scale of the actor in the world.

Flags

RuntimeSync RuntimeParallel ReadOnly

===== Struct(Rotator) Rotation rotation The rotation of the actor in the world.

Flags

RuntimeSync RuntimeParallel ReadOnly

==== Functions

===== Get Power Connectors getPowerConnectors (Array(Trace(PowerConnection)) Connectors connectors out) Returns a list of power connectors this actor might have.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Connectors connectors

Array(Trace(PowerConnection)) out

The power connectors this actor has.

===== Get Factory Connectors getFactoryConnectors (Array(Trace(FactoryConnection)) Connectors connectors out) Returns a list of factory connectors this actor might have.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Connectors connectors

Array(Trace(FactoryConnection)) out

The factory connectors this actor has.

===== Get Pipe Connectors getPipeConnectors (Array(Trace(PipeConnection)) Connectors connectors out) Returns a list of pipe connectors this actor might have.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Connectors connectors

Array(Trace(PipeConnection)) out

The factory connectors this actor has.

===== Get Inventories getInventories (Array(Trace(Inventory)) Inventories inventories out) Returns a list of inventories this actor might have.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Inventories inventories

Array(Trace(Inventory)) out

The inventories this actor has.

===== Get Network Connectors getNetworkConnectors (Array(Trace(ActorComponent)) Connectors connectors out) Returns the name of network connectors this actor might have.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Connectors connectors

Array(Trace(ActorComponent)) out

The factory connectors this actor has.

The actor class has an interesting function getFactoryConnectors.
Let’s check the return type of it:

=== Factory Connection FactoryConnection

Parent

A actor component that is a connection point to which a conveyor or pipe can get attached to.

==== Properties

===== Int Type type Returns the type of the connection. 0 = Conveyor, 1 = Pipe

Flags

RuntimeSync RuntimeParallel ReadOnly

===== Int Direction direction The direction in which the items/fluids flow. 0 = Input, 1 = Output, 2 = Any, 3 = Used just as snap point

Flags

RuntimeSync RuntimeParallel ReadOnly

===== Bool Is Connected isConnected True if something is connected to this connection.

Flags

RuntimeSync RuntimeParallel ReadOnly

==== Functions

===== Get Inventory getInventory (Trace(Inventory) Inventory inventory out) Returns the internal inventory of the connection component.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Inventory inventory

Trace(Inventory) out

The internal inventory of the connection component.

===== Get Connected getConnected (Trace(Inventory) Connected connected out) Returns the connected factory connection component.

Flags

RuntimeSync RuntimeParallel

Return Values
Name Type Description

Connected connected

Trace(Inventory) out

The connected factory connection component.

==== Signals

===== Item Transfer ItemTransfer (Struct(Item) Item item) Triggers when the factory connection component transfers an item.

Flags

Parameters
Name Type Description

Item item

Struct(Item)

The transfered item

Well, look at that, it has a ItemTransfer Signal.
And when looking at the description, it does exactly what we want.

So lets use the information we got from the reflection and write some code that gets a factory connector, and then listen to it.

We don’t know which of the factory connectors the getFactoriesConnector returns.
They will always be in the same order on a per building type basis.
So we simply have to test which of the connectors is the output connector for all constructors, and listen to that one.

local connector = manufacturer:getFactoryConnectors()[1]
event.listen(connector)

So, now we can pull events and print the ItemTransfer event to the console.

while true do
 e, s, i = event.pull()
 if e == "ItemTransfer" then
  print("Transfer!", i)
 end
end

Our full code yet would be:

local manufacturer = component.proxy(...)
local recipe = manufacturer:getRecipe()

print(recipe.name)

local connector = manufacturer:getFactoryConnectors()[1]
event.listen(connector)

while true do
 e, s, i = event.pull()
 if e == "ItemTransfer" then
  print("Transfer!", i)
 end
end