User talk:Braindawg: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Created page with "{{tf2}} This page contains examples of VScript performance tips and tricks for {{tf2|3}}. All of these results come from [https://cdn.discordapp.com/attachments/1...")
 
No edit summary
Line 1: Line 1:
{{tf2}} This page contains examples of [[Vscript|VScript]] performance tips and tricks for {{tf2|3}}.
== Folding Functions ==


All of these results come from [https://cdn.discordapp.com/attachments/1039243316920844428/1147882067749765210/vscript_benchmark_fix.zip?ex=661bd67b&is=6609617b&hm=d118eefea969169e55f54c57b61c46a7e0dfc953e46158ef239327939461b900& This benchmarking tool] '''You must launch the game in -insecure before using this!'''
Folding functions in the context of VScript means folding them into the root table. It is recommended that you do this for functions that are commonly used in expensive operations, and for functions that have unique names that are not shared by other classes. Not only is this more readable and easier to write, but it also skips the extra step where the game needs to first find the function in a table before executing it.


== Folding functions ==
The following example folds all NetProp related functions into the root table.  for example, <code>NetProps.GetPropString(...)</code> would simply become <code>GetPropString(...)</code>.  This can yield performance improvements of up to 20%{{confirm}}


<code lang=js>
foreach(k, v in ::NetProps.getclass())
if (k != "IsValid" && !(k in ROOT))
ROOT[k] <- ::NetProps[k].bindenv(::NetProps)
</code>


== Constants ==


== Iterating through players ==
=== Folding Constants ===


The most common method of iterating over all players in a map is like so:
Similar to folding functions, folding pre-defined Constant values into the constant table (or the root table) makes referencing them less cumbersome, as well as increasing performance.


<source lang=js>
<code lang=js>
::MaxPlayers <- MaxClients().tointeger();
::ROOT <- getroottable();
 
if (!("ConstantNamingConvention" in ROOT)) // make sure folding is only done once
for (local i = 1; i <= MaxPlayers ; i++)
{
{
    local player = PlayerInstanceFromIndex(i)
foreach (a,b in Constants)
    if (player == null) continue
foreach (k,v in b)
    printl(player)
ROOT[k] <- v != null ? v : 0;
}
}
</source>
</code>
 
While this solution is simple and efficient enough for most use cases, the fastest way to iterate over all players is to collect them in a separate array when the player has fully loaded into the server, then iterate over this array when needed.
 
<source lang=js>
::playerarray <- []
 
ClearGameEventCallbacks()


//player is activated and loaded into the server
You may have noticed that we are folding our constants into the root table instead of the constant table. This will be explained below
function OnGameEvent_player_activate(params)
{
    local player = GetPlayerFromUserID(params.userid)


    //check if we're already in the array
=== Root table vs Constant table ===
    if (playerarray.find(player) != null) return
 
    //add player to the array if they don't already exist
    playerarray.append(player)
}
 
//player has left the server
function OnGameEvent_player_disconnect(params)
{
    local player = GetPlayerFromUserID(params.userid)
 
    //cache player length value
    local playerarray_len = playerarray.len()
   
    //reverse through the player array and remove invalid players
    for (local i = playerarray_len - 1; i >= 0; i--)
        if (playerarray[i] == null || playerarray[i] == player)
            playerarray.remove(i)
}
__CollectGameEventCallbacks(this)


//iterate over array
Unlike values inserted into the root table, values inserted into the constant table are cached at the pre-processor level.  What this means is, while accessing them can be faster (up to 1.5x faster to be more precise), it may not be feasible to fold your constants into the constant table
foreach (player in playerarray)
    printl(player)


</source>
If you intend to insert values into the constant table, you must do this ''before'' any other scripts are executed, otherwise your script will not be able to read any values from it.

Revision as of 17:01, 5 April 2024

Folding Functions

Folding functions in the context of VScript means folding them into the root table. It is recommended that you do this for functions that are commonly used in expensive operations, and for functions that have unique names that are not shared by other classes. Not only is this more readable and easier to write, but it also skips the extra step where the game needs to first find the function in a table before executing it.

The following example folds all NetProp related functions into the root table. for example, NetProps.GetPropString(...) would simply become GetPropString(...). This can yield performance improvements of up to 20%[confirm]

foreach(k, v in ::NetProps.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::NetProps[k].bindenv(::NetProps)

Constants

Folding Constants

Similar to folding functions, folding pre-defined Constant values into the constant table (or the root table) makes referencing them less cumbersome, as well as increasing performance.

ROOT <- getroottable();

if (!("ConstantNamingConvention" in ROOT)) // make sure folding is only done once { foreach (a,b in Constants) foreach (k,v in b) ROOT[k] <- v != null ? v : 0; }

You may have noticed that we are folding our constants into the root table instead of the constant table. This will be explained below

Root table vs Constant table

Unlike values inserted into the root table, values inserted into the constant table are cached at the pre-processor level. What this means is, while accessing them can be faster (up to 1.5x faster to be more precise), it may not be feasible to fold your constants into the constant table

If you intend to insert values into the constant table, you must do this before any other scripts are executed, otherwise your script will not be able to read any values from it.