Mapping/Custom Keyvalues

From Sven Co-op
Jump to navigation Jump to search

1 Introduction

Custom keyvalues are a new feature in Sven Co-op 4.6. Using custom keyvalues, you can store any and as much information as you want on any entity with any names you desire. While normal keyvalues will be read into internal data structures of the entity and unknown keyvalues will be discarded, custom keyvalues will simply be stored on the respective entity. The entity won't care about what you set. Custom keyvalues are identified by a leading dollar sign $, followed by a type-specifier. When accessing a custom keyvalue which is unset, the game will read the type-specifier to initialize the variable as either an integer (a whole number), a float (a decimal digit), a vector (a triple of 3 floats) or a string (a text/text-fragment/array of chars) and initialize it with a default value of zero for anything numeric and an empty string for the string type.
The following 4 type specifiers exist, whereas the underscore is part of them:

  • $i_ makes the custom keyvalue an integer. (-2147483648 to 2147483647)
  • $f_ makes the custom keyvalue a float.
  • $v_ makes the custom keyvalue a 3D-vector, consisting of 3 floats.
  • $s_ makes the custom keyvalue a string.


Examples: $i_donutseaten, $f_healthreserve, $v_vectortoenemy, $s_infotext.

A note on the float datatype: This data type can represent huge numbers with over 30 digits before the decimal point, in negative as well as positive number-space. However, the further away the number is from 0.0, the less precise it is represented. For example 10.4 will be so close to 10.4 in the float data type that you can assume they're practically the same, but 10000.4 will actually become about 10000.400391. This is relatively obsolete, depending on how great precision you require.

What a vector is: Simply a grouped set of 3 floats, which is either used to represent pitch, yaw and roll and thus define an angle in 3D-space, or an x-, y- and z-extent to define a direction and distance in 3D-space. E.g. when you take a running jump from the top ofa skyscraper, you end up with great negative z-/height-velocity and some y-/forward-velocity, but not really any x-/right-velocity, e.g. "0.0 300.0 -1800.0", without the quotes, where the single values represent speed in units per second into their according dimensions.

2 Setting Custom Keyvalues

There are different ways to set a custom keyvalue. The most straightforward way is to view an entity's properties in Valve Hammer Editor, disable the Smart-Edit-mode and add the key manually, e.g. key $i_energy and value 50. You can also set custom keyvalues through trigger_changevalue and trigger_copyvalue, or use them as a source to write to another keyvalue (in trigger_copyvalue). You can compare them among each other and normal keyvalues through trigger_condition. You can also set them when creating an entity with trigger_createentity. Custom keyvalues are pretty flexible to store whatever you need and to operate on that however you require.

3 Motivation

The main reason custom keyvalues were implemented was to give mappers an alternative to the few unused base keyvalues to store data on entities. Here are several possible usage scenarios to inspire you:

  • Key $i_fuel on a player: Store a number to represent jetpack fuel remaining.
  • Key $i_keycardlevel on a player: Store a number to represent which level of security doors this player has access to.
  • Key $f_healthreg on monsters: Float to determine how much health to restore per second on a global basis.
  • Key $f_distance on func_train: Float to add travelled distance to, causing power outage when you use it too much over specific amount of time.


4 Custom keyvalues in Angelscript

Custom keyvalues can also be used from Sven Co-op's AngelScript API. Unlike other entity variables, custom keyvalues cannot be directly accessed by name. This is because they are created on demand, and can't be dynamically bound at runtime.

Here's how you access and use custom keyvalues:

Accessing an entity's custom keyvalues:

CBaseEntity@ pEntity = ...;
...
CustomKeyvalues@ kvEntity = pEntity.GetCustomKeyvalues();

This gets the custom keyvalues manager for the entity. You should never store this instance anywhere, only use local variables. If you remove the entity, do not access its custom keyvalues afterwards.

Getting a custom keyvalue:

CustomKeyvalue value( pCustom.GetKeyvalue( "$i_myint" ) );

This gets a custom keyvalue named $i_myint. It has the type of int, which means the custom keyvalues code will force it to convert to an integer internally.

Using a custom keyvalue:

if( value.Exists() )
{
	g_Game.AlertMessage( at_console, "Value: %1\n", value.GetString() );
}
else
{
	g_Game.AlertMessage( at_console, "Value didn't exist!\n" );
}

This checks if the keyvalue actually has a value, and if so, prints it out as a string. Any value can be converted to a string, but not all values can convert to the other supported types. Use value.GetType to get the underlying type as an Entvartype enum value.

Setting a custom keyvalue:

pCustom.SetKeyvalue( "$i_myint", 456 );

This sets the integer keyvalue to integer 456. Note that the code does not check to see if the type specifier matches the type you're setting. If you pass a float to an integer type, it will still convert successfully, and be internally considered as a float. Try to avoid deviating from the name, or avoid using the type specifier if you need to support multiple types.

The keyvalue does not have to exist in order to set it.

Checking if a custom keyvalue exists:

bool fExists = pCustom.HasKeyvalue( "$i_myint" );

Default initializing a keyvalue:

pCustom.InitializeKeyvalueWithDefault( "$i_myint" );

This sets the keyvalue $i_myint to the default value for its type. This is 0 for integer and float, { 0, 0, 0 } for vector, and an empty string for string. Again, the keyvalue does not have to exist to set it.

Removing custom keyvalues: Currently not possible.

Do not try to store a CustomKeyvalue instance directly: the class can only be default constructed (no value), or copy constructed (value from CustomKeyvalues::GetKeyvalue). This is to prevent you from having a reference to a keyvalue whose memory has been freed. For safety purposes, do not try to access custom keyvalues when the entity from which they came has been removed.