PDA

View Full Version : [HOWTO] Using XVars


Exolent[jNr]
09-23-2010, 18:14
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 (https://forums.alliedmods.net/showpost.php?p=1307575&postcount=8)).




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:
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:
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:
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:
// 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:
// 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 (http://www.amxmodx.org/funcwiki.php?search=xvar&go=search).

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:
// 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!" );
}
}
// 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:
#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"

All feedback and suggestions are welcome.

fysiks
09-23-2010, 18:30
Excellent Exolent! Previously I had very little knowledge about these but I did get them to work by looking at other plugins. This will make it easier to use this neat feature.

Any idea on speed relative to cvars or pcvars? Just curious.

Exolent[jNr]
09-23-2010, 18:54
Any idea on speed relative to cvars or pcvars? Just curious.

No, I've never used the profiler or anything.
But since they aren't the same as cvars (Xvars being security to plugins only) I think the choice between the 2 should be based on how they are needed.

RedRobster
09-23-2010, 22:57
Very useful stuff, thanks for the info.

ConnorMcLeod
09-24-2010, 01:33
;1307004']No, I've never used the profiler or anything.
But since they aren't the same as cvars (Xvars being security to plugins only) I think the choice between the 2 should be based on how they are needed.

I think that speed should be considered in some situations.


So, you said that set_xvar_XXX works only in the "main" plugin ?
Or is this the way to set an xvar from an outside plugin ?


Also, i think that native xvar_exists is useless when get_xvar_id does actually the same + returns the index.

Exolent[jNr]
09-24-2010, 02:36
I think that speed should be considered in some situations.

True, but I said what I said because I could not give information about speed difference.

So, you said that set_xvar_XXX works only in the "main" plugin ?
Or is this the way to set an xvar from an outside plugin ?

The [get|set]_xvar_[num|float] work in the main plugin and the outside plugins.
However it is useless to use them in the main plugin since you have direct access to them.

Also, i think that native xvar_exists is useless when get_xvar_id does actually the same + returns the index.

You're right, but the native exists (remember this is in AMXX and cannot be changed) so it's more logical to use it rather than checking it's ID for -1.

abdul-rehman
09-24-2010, 06:02
Thnx Exolant i didnt even know about these :D

ConnorMcLeod
09-24-2010, 13:21
It appears that get_pcvar_num and get_xvar_num are executed with the same speed.
fake natives are slower.

Plugins 1 :
#include <amxmodx>

#define VERSION "0.0.1"
#define PLUGIN "xvar profile 1"

public xvar1 = 10

public plugin_init()
{
register_plugin(PLUGIN, VERSION, "ConnorMcLeod")
register_cvar("amx_cvar_test", "1337")
}

public plugin_natives()
{
register_native("get_variable_test", "get_variable_test")
}

public get_variable_test()
{
return xvar1
}

Plugin 2 (profiled) :
#include <amxmodx>

#define VERSION "0.0.1"
#define PLUGIN "xvar profile 2"

native get_variable_test()

public plugin_init()
{
register_plugin(PLUGIN, VERSION, "ConnorMcLeod")
}

public plugin_cfg()
{
new pcvar = get_cvar_pointer("amx_cvar_test")
new xvar = get_xvar_id("xvar1")

for(new i; i<1000; i++)
{
get_pcvar_num(pcvar)
get_xvar_num(xvar)
get_variable_test()
}
}


Dump :
date: Fri Sep 24 19:18:23 2010 map: de_aztec
type | name | calls | time / min / max
-------------------------------------------------------------------
n | register_plugin | 1 | 0.000001 / 0.000001 / 0.000001
n | get_cvar_pointer | 1 | 0.000001 / 0.000001 / 0.000001
n | get_xvar_id | 1 | 0.000001 / 0.000001 / 0.000001
n | get_pcvar_num | 1000 | 0.000180 / 0.000000 / 0.000000
n | get_xvar_num | 1000 | 0.000179 / 0.000000 / 0.000000
n | get_variable_test | 1000 | 0.000245 / 0.000000 / 0.000001
p | plugin_cfg | 1 | 0.000561 / 0.000561 / 0.000561
p | plugin_init | 1 | 0.000001 / 0.000001 / 0.000001
0 natives, 0 public callbacks, 2 function calls were not executed.

Exolent[jNr]
09-24-2010, 13:56
It appears that get_pcvar_num and get_xvar_num are executer with the same speed.
fake natives are slower.

Thanks for the useful info. It's been added to the first post.

Arkshine
09-24-2010, 15:17
The speed is really trivial here and not worth to be mentioned. The choice should be more considering the user's preference or plugin design, not the speed. Just my opinion.

Seta00
09-24-2010, 17:05
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.

Exolent[jNr]
09-24-2010, 20:22
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.

I thought that information was implied, but I suppose it would be necessary to be stated.

Vechta
09-25-2010, 03:23
Nice, thanks for posting

t3hNox
11-20-2010, 14:14
Thanks. This is pretty usefull !
Is there any way to detect when the xvar value is altered in the main plugin ?

fysiks
11-20-2010, 14:19
Thanks. This is pretty usefull !
Is there any way to detect when the xvar value is altered in the main plugin ?

Probably the only way is to constantly check it's value to see if it has changed but that is not a good idea.

Exolent[jNr]
11-20-2010, 14:29
Thanks. This is pretty usefull !
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.

schmurgel1983
08-28-2011, 08:31
thanks Exolent,
i never hear about xvars. but sounds good.

Kia
04-03-2012, 06:45
Hey,
Just wanted to try this out but I have a Problem.

In my first Plugin I wrote :


public bool:g_bHasWH[33]


And in my second :


new bool:g_bHasWH2[33]


public plugin_init()
{
g_bHasWH2 = get_xvar_num(g_bHasWH)
}


But it says :
Error: Undefined symbol "g_bHasWH"

What do I have to do to get it working?

Arkshine
04-03-2012, 06:49
You can't use xvars with arrays, you will have to use dynamic natives for that.

MokeN
06-27-2012, 16:31
awesome.