Skip to content

Lua Event System⚓︎

API: LuaEvents

Events are a crucial part of any game, this includes the Massive Loop. The majority of events can be traced back to player interactions. However, the scripts also can raise events based on some criteria.

The Lua Event System in Massive Loop is a versatile tool used to manage and communicate not only with other parts of the game but it can also be used to synchronize the game between all players over the network.

It's all about the handlers⚓︎

Handlers: Lua functions that will get executed when an event triggers.

In Massive Loop, the only way to create an Event is to attach handlers to it.

Attaching handlers: Specifying the function that will execute when an event triggers.

When attaching a handler to an Event, the system keeps a record of the specified event name and the functions to execute. Adding more handlers to that event just adds them to that record.

Warning

Raising an event is pointless if there are no handlers to handle the event.

Adding Handlers:⚓︎

To add a handler to an event, use the following method (from API)

LuaEvents.Add(eventName, handler);

The eventName is a string that defines the name of the event.

handler is a function that will be executed when the event triggers.

Example

function handler()
   Debug.log("The event triggered"); 
end

LuaEvents.Add("AnEventName", handler)

Note that in Lua, like many other programming languages, you can pass the reference to a function by typing its name without parenthesis.

You can add many handlers to same event:⚓︎

function handler1()
   Debug.log("Handler 1"); 
end

function handler2()
   Debug.log("Handler 2"); 
end

LuaEvents.Add("EventName", handler1);
LuaEvents.Add("EventName", handler2);

Tip

Keep handlers lightweight in terms of computation. If there are 1000 handlers attached to an event, all those handlers will get executed in one single frame when the event triggers. This may cause performance issues.

It is recommended to keep the number of handlers per event as low as possible.

If a handler requires you to initiate a costly computation, you can have a bool value in your script in which the handler will set to true. Then, in update(), check for that variable and if it's true, start a coroutine to perform the calculation. Learn more about Coroutines.

do -- entity
    local entityScript = LUA.script;

    local startComputation = false;

    function handler()
        startComputation = true;
    end

    function entityScript.Start()
        LuaEvents.Add("anEvent", handler);
    end

    function entityScript.Update()
        if startComputation then
            entityScript.startCoroutine(heavyComputation);
        end
    end

    local function heavyComputation()
        startComputation = false;
        -- perform heavy computations here
        -- don't foget to call yield
        -- ...
        coroutine.yield();
        -- ...

    end

end

Raising the events⚓︎

An event can be raised in different ways.

One way to raise an event is by its name. You can call the Invoke method (From any script) to raise an event. For example:

LuaEvents.Invoke("AnEventName"); 

You can pass optional parameters in the invoke function which will get passed to a handler function.

For example, you can define the following handler:

function handler(message)
    Debug.Log("I received the message"..message);
end

LuaEvents.Add("onMessageReceived", handler);

And invoke it like this:

LuaEvents.Invoke("onMessageReceived", "Hello there");

You can raise an event over the network as well.

Every handler that is attached to an event can be raised over the network. You don't need anything else.

It is important to remember that all of the clients (players who joined the room) will have access to all Lua scripts.

Caution

It's important that the handler must be registered before raising an event. The event handlers which are added to a master-only script, will not be raised on non-master clients when the event triggers.

To raise an event over the network, you can call any of these methods instead of plain invoke().

  1. .invokeForAll()
  2. .invokeForOthers()
  3. .invokeForMaster()
  4. .invokeForMasterOnly()

For more detail about networking events, please check out this tutorial on multiplayer and networking.

Removing handlers⚓︎

To remove a handler, you can call the LuaEvents.remove() function. All registered handlers can be traced by their LuaEventId's. The LuaEventId is a unique identifier for a handler that is attached to a specific function.

The Add function returns the specific ID for the attached handler.

function handler()
    Debug.Log("event");
end

myHandlerId = LuaEvents.Add("eventName", handler);

To remove the handler define above,

LuaEvents.Remove(myHandlerId);

Tip

Although small, all registered handlers occupy a space in memory. Remove unnecessary handlers.

Warning

Try to add all your event handlers in the start function.

Local events⚓︎

A Local event only defined with in the script and the game object. So, for example lets imagine a local event called testEvent within a Lua script test.lua attached to game object A. The scope of this event is only the combination of the object A and test.lua. Same event name in same script attached to a different object will be different from this event. Or a local event with same name in object A with in a different script would in a separate scope.

Local Events over the network!⚓︎

Ironically, the local events can be raised over the network! In this case, the scope of the local event is within the same game object + Lua script combination that existed in the scene during the build time, or the instantiated prefab instance with MLSynchronizer.

Handling UI Events⚓︎

The Lua Event System can be used to register events from UI. The concept of registering a handler for UI events is exactly the same. In any script, you can register a handler for the events.

For example, consider following sample UI Canvas with a panel and a Button. Check out the tutorial on UI to learn about working with UI in Massive Loop.

Registering UI event handlers⚓︎

To add the event handler, like previous scenarios, we add the event handler first (in any script)

do -- UI 
    local UIscript = LUA.script;

    function onButtonClick()
        Debug.Log("Button clicked");
    end

    function UIscript.Start()
       LuaEvents.Add("onMyButtonClick", onButtonClick); 
    end


end

Again, so far it is the exact process.

Raising UI events⚓︎

We need to connect the Canvas element to the Massive Loop Lua Event system. In order for the UI to register the user interactions in VR, we must add the SDKUI component to our canvas.

To do this, Select your canvas from the scene objects hierarchy, and in the inspector click on Add Component then select MassiveLoop > UI > SDKUI.

As you may notice, adding SDKUI component also adds a LuaUIEvent component automatically. This component can be used to raise UI events.

In our example, we want to register the click from the button, and raise the event we named "onMyButtonClick".

In order to do that, first, choose the Button from the scene hierarchy and find the On Click () box in the inspector.

Click on the + .

Here, we need to drag the Canvas object (Which has the LuaUIEvent component on it) and drop it to the empty field.

Now, from the function drop down, select LuaUIEvents > CallLuaEvent(string).

Now on the empty field that opened, we can write the name of the event we want this button to trigger.

Done! Now whenever a user clicks this button, all the handlers registered under name of "onMyButtonClick" will be executed.

A word on event names⚓︎

As we saw in previous sections, the event names are strings, which technically allows the event names have a little more flexibility. Although it is allowed to go wild on naming the event names, we recommend selecting a naming convention similar to camelCase, snake_case or, etc. that suits your project.

Info

Under the hood, the event names are stored in a hash table. There is no string comparison used.