In-depth NetEvents guide
As explained in the Introduction to VeniceEXT concepts guide, NetEvents are a way for mods to exchange information between their client-side and server-side scripts over the network. In this guide we'll go in a bit more detail on how NetEvents work and how to use them. Before reading this guide make sure you first have a good understanding of how regular Events work.
Similar to regular Events, every NetEvent is identified by a unique string name and can have some data associated with it. NetEvent names are case sensitive.
Subscribing to NetEvents
Subscribing to NetEvents works in a similar way to subscribing to regular Events but with some small differences based on where the NetEvent is being received.
On the client
NetEvents:Subscribe('MyServerNetEvent', function(data) print('Got NetEvent from server with data:') print(data) end)
We also pass in a handler function that will get called whenever this NetEvent is received. In this case, when the server sends us the
MyServerNetEvent NetEvent, the client script will print
Got NetEvent from server with data: followed by the associated NetEvent data.
On the server
NetEvents:Subscribe('MyClientNetEvent', function(player, data) print('Got NetEvent from player ' .. player.name .. ' with data:') print(data) end)
The only difference to the client-side version is that the handler function accepts an extra argument as its first argument which signifies the player the event was sent from. That means that the first argument of the handler function will be a Player object, with the NetEvent data coming after it. In the example above, as soon as our server receives the
MyClientNetEvent NetEvent from a client, the handler function will be called and
Got NetEvent from player PlayerName with data: will be printed (but instead
PlayerName we will see the name of the player who sent that event), followed by the associated NetEvent data.
NetEvent user data
Similar to regular Events, there are versions of the Subscribe method that allow us to pass some custom user data that will be provided to our NetEvent handler function alongside all of the NetEvent data as seen in the examples below:
-- This is a client-side script. local x = 123 NetEvents:Subscribe('MyServerNetEvent', x, function(userData, data) print(x) end)
-- This is a server-side script. local x = 123 NetEvents:Subscribe('MyClientNetEvent', x, function(userData, player, data) print(x) end)
Both of these examples will print
123 when the respective NetEvents are received. Keep in mind that on the server-side script example, the
userData is passed before everything else, including the Player object.
Stop receiving events
You may want to stop receiving specific NetEvents at some point. There are a few different ways to do that:
Using the NetEvent object
local netevent = NetEvents:Subscribe(...) -- Some time later. netevent:Unsubscribe()
After you call that method you will no longer receive that NetEvent and the handler function will never get called again until you subscribe to it again.
Unsubscribing by name
This will make it so no
MyNetEvent NetEvents are received by your mod until you explicitly subscribe to them again.
You can use the same Unsubscribe method without passing an event name in to stop receiving all subscribed to NetEvents:
Now that we know how to listen for NetEvents we also need to see how to send them between the server and the clients or vice-versa. The way we do that differs slightly between the server and the client.
Server to client
NetEvents:Broadcast('MyServerNetEvent', 'hello client!')
In this example, the
hello client! string is the custom data we want to send alongside the
MyServerNetEvent NetEvent. If on the client-side you use the same subscription code as the example above then the client will print
Got NetEvent from server with data: hello client!.
local player = PlayerManager:GetPlayerByName('NoFaTe') if player ~= nil then NetEvents:SendTo('MyServerNetEvent', player, 'hello client!') end
In this example, we try to get the Player object for the connected player with the name
NoFaTe by using the GetPlayerByName method of the PlayerManager library, and if that player exists (i.e. if the method doesn't return
nil) then we send the
MyServerNetEvent NetEvent specifically to that player with the
hello client! string as the custom data. This will make it so only this specific player (and their corresponding client-side scripts) will receive this event.
Client to server
NetEvents:Send('MyClientNetEvent', 'hello server!')
In this example we send the
MyClientNetEvent NetEvent to the server with the
hello server! string as the custom data. If on the server-side you use the same subscription code as the example above then the server will print
Got NetEvent from player PlayerName with data: hello server!.
By default, any NetEvents you send will be received by all loaded mods. As with regular Events, there are
Local versions of all the NetEvent sending methods that will make it so the NetEvent is only received by your own mod, even if other mods subscribe to it:
You can pass any amount of data you want (or no data) as additional parameters to the Send, SendTo, and Broadcast methods (and their variants), however there are some restrictions to the type of data you can use. More specifically, only the following types are allowed:
- Lua numbers
- Lua strings
- Lua booleans
- Vec2 objects
- Vec3 objects
- Vec4 objects
- LinearTransform objects
- Guid objects
- AxisAlignedBox objects
- QuatTransform objects
- Quat objects
- Lua tables with keys and values of any of the above types (or other tables)
By default, when you send NetEvents, they are guaranteed to be received by the receiving end and in the order you sent them.
NetEvents:Broadcast('MyNetEvent1') NetEvents:Broadcast('MyNetEvent2') NetEvents:Broadcast('MyNetEvent3')
In the example above, it is guaranteed that all clients will receive these three NetEvents and in the order we sent them, with
MyNetEvent1 being received first, followed by
This behavior is desirable in general, but it has some negative side-effects. More specifically, because network conditions are not always ideal, some NetEvents might get lost in transit which will force VeniceEXT to keep retrying to send them until they are received by the other side. There's also the case that they are received out-of-order. This means that the receiving side has to wait until everything is received and processed in order before being to process any more NetEvents, which can lead to long delays.
For this reason, VeniceEXT provides two additional reliability modes when sending NetEvents, that allow you to better control this behavior:
By using the
Unreliable variants of the sending methods (SendUnreliable, SendUnreliableTo, and BroadcastUnreliable) we tell VeniceEXT that we want absolutely no reliability guarantees. This means that NetEvents sent using those methods are not guaranteed to be received by the receiving side or to be processed in the order they were sent it. They could get lost in transit or received completely out-of-order. If you are lucky, they might get received and be in-order.
Unreliable ordered NetEvents
By using the
UnreliableOrdered variants of the sending methods (SendUnreliableOrdered, SendUnreliableOrderedTo, and BroadcastUnreliableOrdered) we tell VeniceEXT that we only want ordering guarantees. This means that NetEvents sent using those methods are not guaranteed to be received by the receiving side, but when they are, they will be processed in the order they were sent.
NetEvents:BroadcastUnreliableOrdered('MyNetEvent1') NetEvents:BroadcastUnreliableOrdered('MyNetEvent2') NetEvents:BroadcastUnreliableOrdered('MyNetEvent3')
In the example above, if we assume that
MyNetEvent1 got lost in transit, then
MyNetEvent3 was received, followed by
MyNetEvent2, only the
MyNetEvent3 will be processed and
MyNetEvent2 will be discarded.
Next, you can read a more in-depth guide on Hooks and how to use them.