View Single Post
Silvers
SourceMod Plugin Approver
Join Date: Aug 2010
Location: SpaceX
Old 05-25-2023 , 15:06   Re: [L4D2] Survivor Bot AI Improver
Reply With Quote #9

Since some players are mentioning performance issues I thought I would have a look and recommend some changes.


- You have some "FindConVar" within the think function and other places in code that you could place in plugin start to optimize the performance. Hooking the convar for change and using a variable instead of retrieving the value from the convar each time.


- "if (hWeaponList == null)delete hWeaponList;" and "if (hWepArray == null)delete hWepArray;" is not necessary, it's already null, no need to use delete here. Remove the whole line. Maybe there are other null checks you should remove, I only saw these skimming through.


- You should probably re-write "GetSurvivorTeamItemCount" and store the equipped weapons/items each player has when they equip it, instead of constantly looping through all clients and weapons checking what they have. Use SDKHook_WeaponEquipPost and store the weapon type in an array such as: "int g_iPlayerItems[MAXPLAYERS+1][6]" and instead of checking for the string, check for the weapon type ID instead. A list of weapon types and IDs can be found in left4dhooks.


- In some functions that are accessed a lot, especially from Think functions you could optimize the strings by changing "char" to "static char" so it's not re-created each time, unless (which I doubt anyway) you're expecting an empty string without writing data to it first before reading. You could probably change all the strings to this to save some CPU cycles.


- You don't need to use "strcopy" when assigning a string to something, for example:
PHP Code:
strcopy(sAimBonesizeof(sAimBone), (bIsUsingOldSkeleton "ValveBiped.Bip01_Head1" "bip_head")); 
you could just do:
PHP Code:
sAimBone = (bIsUsingOldSkeleton "ValveBiped.Bip01_Head1" "bip_head"); 

- In "OnPlayerRunCmd" you should probably move "if (!IsClientSurvivor(iClient)) return Plugin_Continue;" to the top before pulling the origin/nav area data.


- I don't know if the compiler optimizes for things like this, but instead of "500.0*500.0" just write "250000.0", there are multiple others like this.


- "GetWeaponMaxAmmo" could be optimized using a StringMap to search for the string and return the weapon ID instead, although I'm not sure the string checks are even necessary since you're using "GetWeaponAmmoType", looks like all the types are covered here. Again FindConVar here could be put into plugin start.


- "CheckEntityForItem" could be optimized to remove all the string checks, and match by weapon/item ID instead.


- "ShouldUseFlowDistance" could be optimized slightly to avoid calling the same native twice, by changing it to:
PHP Code:
bool ShouldUseFlowDistance()
{
    if( (!
L4D_IsSurvivalMode() && !L4D2_IsScavengeMode() )
    {
        
int stage L4D2_GetCurrentFinaleStage();
        if( (
stage == 18 || stage == 0) )
        {
            return 
true;
        }
    }

    return 
false;

Maybe applicable to other parts of the code to store a temporary variable instead of calling the same natives multiple times, I didn't check.


- It might be better to use "OnEntityCreated" instead of "ScanMapForEntities" in a timer since you're only checking for "witch" and "weapon_*" entities. Also: "FindEntityByClassname(-1, "*")" would probably be faster than looping through all entities as the function is currently doing. Or maybe: FindEntityByClassname(-1, "witch"); and: FindEntityByClassname(-1, "weapon*);
Might be a good idea to benchmark test and see which is the faster method.


- "g_hWitchList" could be initialized with "g_hWitchList = new ArrayList(2);" and set witch ref into index 0 and userid into index 1, instead of nesting multiple ArrayLists within the g_hWitchList ArrayList:
For example:
PHP Code:
int index g_hWitchList.Push(EntIndexToEntRef(iEntity));
g_hWitchList.Set(indexhEvent.GetInt("userid")); // or set to "0" as done when you initialize the array. 

- You might want to call "ClearEntityArrayLists" on "round_end" event too, for round restarts or versus 2nd round


- "Event_OnWeaponFire" could be optimized to use StringMap.ContainsKey or StringMap.GetValue to check if the weapon classname is correct. It might be optimized further by calling "GetRandomInt" for shotgun/sniper first then checking the strings if the value is 1. I would benchmark test if that's faster than comparing 2 strings that don't match. Also "static char" since its called often and you're filling the string data first before reading. The return within the if statement is unnecessary.


There are probably other areas that could be optimized, this is just what I noticed skimming through.

__________________

Last edited by Silvers; 05-25-2023 at 15:22.
Silvers is offline