Event System
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Event System
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: 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.
EventToken MLEvents.AddHandler(string eventName, Action<object[]> 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
using ML.SDK;
using UnityEngine;
public class Script : MonoBehaviour
{
private void Handler(object[] arguments)
{
// code to run
}
void Start()
{
MLEvents.AddHandler("AnEventName", Handler);
}
}
Note
You can pass the reference to a function by typing its name without parenthesis.
You can add many handlers to same event:
using ML.SDK;
using UnityEngine;
public class Script : MonoBehaviour
{
private void Handler1(object[] arguments)
{
// code to run for handler 1
}
private void Handler2(object[] arguments)
{
// code to run for handler 2
}
void Start()
{
MLEvents.AddHandler("AnEventName", Handler1);
MLEvents.AddHandler("AnEventName", 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.
using ML.SDK;
using System.Collections;
using UnityEngine;
public class Script : MonoBehaviour
{
private void Handler(object[] arguments)
{
StartCoroutine(CoroutineFunction());
}
private IEnumerator CoroutineFunction()
{
// perform heavy computations here
// don't forget to call yield
yield return null;
}
void Start()
{
MLEvents.AddHandler("AnEventName", Handler);
}
}
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:
MLEvents.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:
using ML.SDK;
using UnityEngine;
public class Script : MonoBehaviour
{
private void Handler(object[] arguments)
{
Debug.Log($"I received the message {arguments[0]}");
}
void Start()
{
MLEvents.AddHandler("AnEventName", Handler);
}
}
And invoke it like this:
MLEvents.Invoke("AnEventName", "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.
To raise an event over the network, you should call InvokeNetwork
of these methods instead of plain invoke()
.
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 a token for the attached handler which can be used to remove it later.
using ML.SDK;
using UnityEngine;
public class Script : MonoBehaviour
{
EventToken eventToken;
private void Handler(object[] arguments)
{
Debug.Log($"I received the message {arguments[0]}");
}
void Start()
{
eventToken = MLEvents.AddHandler("AnEventName", Handler);
}
private void OnDisable()
{
MLEvents.RemoveHandler(eventToken);
}
}
Tip
Although small, all registered handlers occupy a space in memory. Remove unnecessary handlers.
Warning
For the Lua scripts, 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.
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.