[HOWTO] Using XVars

For scripting examples for learning how to use AMXX.
User avatar
Archive-Poster
Posts: 1347
Gender:
United States of America

[HOWTO] Using XVars

Post by Archive-Poster »

About XVars
XVars are public variables that can be accessed across plugins.
They work and look like normal variables inside of the plugin creating them, but have to be accessed a different way in the other plugins.

Purpose:
XVars should be used instead of CVars when the variables need to be private to the plugins.
XVars cannot be changed from the server console or by any existing command unless a plugin is made for that purpose.
It basically provides security to variables.

If you have dynamic natives who's purpose is to only share a variable between plugins, XVars should be used instead.
Dynamic natives are a bit slower than using XVars (see Connor's post).

Creating:
When creating XVars, they need to be global and public.
What this means is that they should not be inside any function when created and must be prefixed with public instead of new or stock.

Example:

Code: Select all

public ExampleXvarVariable;
public bool:ExampleXvarBoolean = true;
public Float:ExampleXvarFloat = 3.14;
Inside the plugin that created them, they work just like normal variables.
Assigning values and accessing values works just the same.

XVars only support cells (integers, floats, bools, etc.).
Arrays (including strings, since strings are arrays of characters) cannot be used with XVars.

Cross-Plugin:
When accessing XVars from another plugin, you have to use specific natives.

First, you need to get the XVar's unique identifier:

Code: Select all

new g_pExampleXvarVariable;
new g_pExampleXvarBoolean;
new g_pExampleXvarFloat;

public plugin_init( )
{
    // get the XVar's unique identifier and store for usage throughout the plugin
    g_pExampleXvarVariable = get_xvar_id( "ExampleXvarVariable" );
    
    // check if the XVar is valid
    if( g_pExampleXvarVariable == -1 )
    {
        set_fail_state( "XVar did not exist: ExampleXvarVariable" );
    }
    
    // repeat above for other 2 XVars
}
If you are just interested in checking if the XVar is valid, you can do this:

Code: Select all

public plugin_init( )
{
    // check if the XVar is valid
    if( !xvar_exists( "ExampleXvarVariable" ) )
    {
        set_fail_state( "XVar did not exist: ExampleXvarVariable" );
    }
    
    // repeat above for other 2 XVars
}
To access an XVar's value, you can use these two natives:

Code: Select all

// get integer value
new iValue = get_xvar_num( g_pExampleXvarVariable );

// get boolean value
new bool:bValue = bool:get_xvar_num( g_pExampleXvarBoolean );

// get float value
new Float:flValue = get_xvar_float( g_pExampleXvarFloat );
To set an XVar's value, you can use these two natives:

Code: Select all

// set integer value
set_xvar_num( g_pExampleXvarVariable, 10 );

// set boolean value
set_xvar_num( g_pExampelXvarBoolean, false );

// set float value
set_xvar_float( g_pExampleXvarFloat, 19.6 );
For more information on the natives, read the funcwiki.

Note: The plugin creating the variable does not have to be above the other plugins that are accessing the variable in the plugins.ini.

Duplication:
Plugins can have the same public variables without compilation error or runtime error.
The only effect on this is where the value is being changed/retrieved.
The first plugin that creates the public variable is the plugin that will be affected by it's value and will send the value to other plugins with get_xvar_*().

Here is an example:

Code: Select all

// This is plugin #1 in the plugins.ini

#include < amxmodx >

public DisplayRoundMessage;

public plugin_init( )
{
    register_plugin( "New Round Display", "0.0.1", "Exolent" );
    
    register_event( "HLTV", "EventNewRound", "a", "1=0", "2=0" );
}

public EventNewRound( )
{
    if( DisplayRoundMessage )
    {
        client_print( 0, print_chat, "A new round has started!" );
    }
}

Code: Select all

// This is plugin #2 in the plugins.ini

#include < amxmodx >

public DisplayRoundMessage;

public plugin_init( )
{
    register_plugin( "New Round Display", "0.0.1", "Exolent" );
    
    register_event( "HLTV", "EventNewRound", "a", "1=0", "2=0" );
}

public EventNewRound( )
{
    if( DisplayRoundMessage )
    {
        client_print( 0, print_chat, "A new round has started!" );
    }
}
Yes, they are the same plugin so it's a weak example, but it gets the idea across.
Okay, so these 2 plugins have the same public variable.
If we had this plugin:

Code: Select all

#include < amxmodx >

public plugin_init( )
{
    register_plugin( "New Round Display Enabler", "0.0.1", "Exolent" );
    
    new pDisplayRoundMessage = get_xvar_id( "DisplayRoundMessage" );
    
    if( pDisplayRoundMessage != -1 )
    {
        set_xvar_num( pDisplayRoundMessage, 1 );
    }
}
This would only affect the first plugin's variable and the second plugin would still not show the message.

Extra Notes:
My test files can be used if you need any more understanding of how they work.
xvar_holder.sma is above xvar_finder.sma in the plugins.ini.
The commands that mimic natives require the same arguments, just in command format.
Example: get_xvar_id1 "SomeXvarVariable"
Attachments
xvar_holder.sma.zip
(1.03 KiB) Downloaded 6 times
xvar_finder.sma.zip
(1 KiB) Downloaded 5 times
User avatar
Archive-Poster
Posts: 1347
Gender:
United States of America

Re: [HOWTO] Using XVars

Post by Archive-Poster »

Just to make it clear, the public keyword means the variable is exposed to the host, which is AMXx in this case.

Also XVars, unlike CVars, are not part of the engine, they are an AMXx feature.
Is there any way to detect when the xvar value is altered in the main plugin ?
If you want to hook when it's changed, you would be better off using dynamic natives to change a global variable.
Then you would know when the native is called for when it was changed.

And you can't use xvars with arrays, you will have to use dynamic natives for that.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests