User Messages

From GMod Wiki

Jump to: navigation, search
Lua: User Messages
Page white text.png Description:How to use usermessages
link=User:Nevec Original Author:Nevec
Calendar.png Created:August 23, 2010

Contents

Introduction

Client side and server side are two separate realms. You can't simply call a function on the server and have it execute on the client as well, or set a variable on the client and have it update on the server. Usermessages allow you to send data and trigger functions on one or all clients from the server.

The system works like this:

This article assumes that you know the basics of GMod-specific Lua.

Size limit

Usermessages, unfortunately, have a maximum size of 255 bytes. If this limit is exceeded, the usermessage will not be sent. The most common method of exceeding the limit is sending strings. Methods of how to overcome this limit are explained later.

Every type of value has a size:

Length of the message's identifier is also added to the size + 1.

Examples

Simple Usermessage

Server side code:

 
// start a usermessage with the unique identifier "MyUsermessage"
// this usermessage will be sent to every client on the server as soon as this code is run
umsg.Start( "MyUsermessage" );
// send the usermessage
umsg.End();
 

Client side code:

// define a callback function that will be called when the usermessage is received
local function RecvMyUmsg()
 
	// print something to the console
	print( "MyUsermessage was received!" );
 
end
// hook the callback function to the usermessage
// when the client receives "MyUsermessage", RecvMyUmsg will be called
usermessage.Hook( "MyUsermessage", RecvMyUmsg );

Usermessage with data

Lets expand on the previous example.

Serverside code:

 
umsg.Start( "MyUsermessage" );
	umsg.String( "My string" );
	umsg.Float( 123.456 );
	umsg.Long( 123456 );
	umsg.Bool( false );
umsg.End();
 

Clientside code:

 
// a single argument gets passed to the callback function: a bf_read object that contains the data you sent
// the object will still be there if you send an empty usermessage
local function RecvMyUmsg( data )
 
	print( "String: "..data:ReadString() );
	print( "Float: "..data:ReadFloat() );
	print( "Long: "..data:ReadLong() );
	print( "Boolean: "..data:ReadBool() );
 
end
usermessage.Hook( "MyUsermessage", RecvMyUmsg );

Note: You need to read data in the same order as you send it. If you sent a string first, read it first, etc.

Note: Usermessages are sent as soon as umsg.End() is called, if the code is located in the body of a file, it will be sent as soon as the file has loaded, often before the client's lua has loaded, resulting in him not receiving the message. Send usermessages primarily when hooks are called, or using timers to make sure there is an audience for the message. Send data the client needs immediately upon joining in a PlayerInitialSpawn hook for example.

Practical example

You are making a server administration addon, for instance, and you want the menu to have a list of maps that are available on the server. Since your map list and the server's may differ, you need to manually send the map names.

The server can have hundreds of maps, in which case the whole list may not fit in a single message. This is a good place to use datastream, but, for the sake of this article, we will use plain usermessages.

Server:

local function PlayerInitialSpawn( pl )
 
	// find every map
	for i, mapName in ipairs( file.Find( "../maps/*.bsp" ) ) do
 
		// send a usermessage for every map
		umsg.Start( "AddMap", pl );
			umsg.String( mapName );
		umsg.End();
 
	end
 
end
hook.Add( "PlayerInitialSpawn", "SendMapList", PlayerInitialSpawn );

Client:

// define a table that will keep all of the maps
local MapList = {};
 
// define a callback function for the usermessage
local function AddMap( data )
 
	// insert the received map name into the table of maps
	table.insert( MapList, data:ReadString() );
 
end
usermessage.Hook( "AddMap", AddMap );

Recipient Filter

The second argument for umsg.Start is a recipient filter object. If you want to send the usermessage to every player on the server don't supply this argument at all. If you want to send it to a single player, supply the player object instead. If you want to send it to specific players, use the RecipientFilter object.

local filter = RecipientFilter();
filter:AddPlayer( pl1 );
filter:AddPlayer( pl3 );
 
umsg.Start( id, filter );
umsg.End();

Client to Server

There is no way to send usermessages from client to server. You have to use concommands for this. Console commands are essentially the same as usermessages, except they send the data in string form, whereas usermessages send the data in binary form. The long number 1238419 will take up only 4 bytes when sent in a umsg, but 7 bytes when sent in a concommand.

Concommands have the same limit of 255 bytes.

Datastream

Datastream is essentially a wrapper for concommands and usermessages that allows you to send complex tables and exceed the size limit. It does this by serializing the input before sending and deserializing after receiving. Once the data is serialized into a string, it is sent using multiple usermessages or console commands. Datastream can also be used for sending data from client to server.

You should only use datastream when sending complex tables or very long strings. Datastream makes sending complex structures very easy, but it sacrifices performance.

See Also

Personal tools
Namespaces
Variants
Actions
Navigation
Lua Scripting
Functions
Hooks
Toolbox