punteroo / TF2-Item-Plugins

SourceMod plugins for TF2 that allow players to manage their weapons (australium, festivizer, unusuals, spells, war paints) and cosmetics (unusuals, paints, spell paints, halloween spells). Now with SQLite support.
GNU General Public License v3.0
31 stars 4 forks source link

[ERROR] [SM] Exception reported: Client index 60 is invalid #33

Closed vexx-sm closed 2 months ago

vexx-sm commented 2 months ago

I've tried using the plugins, v4, They ended up throwing a fit in my logs and breaking half way through operation. Note, I've compiled the plugins myself with no issue, all the requirements/perquisites & file structure is intact. The plugins were installed on a clean server which only has the prerequisites listed here and the latest versions of both SourceMod & MetaMod.

Errors log with v 4.0.0 :

L 09/02/2024 - 03:38:50: SourceMod error session started
L 09/02/2024 - 03:38:50: Info (map "itemtest") (file "c:\users\asus\desktop\tf2 server\tf2\tf\addons\sourcemod\logs\errors_20240902.log")
L 09/02/2024 - 03:38:50: [SM] Exception reported: Client index 60 is invalid
L 09/02/2024 - 03:38:50: [SM] Blaming: tf2itemplugin_cosmetics.smx
L 09/02/2024 - 03:38:50: [SM] Call stack trace:
L 09/02/2024 - 03:38:50: [SM]   [0] IsClientInGame
L 09/02/2024 - 03:38:50: [SM]   [1] Line 65, tf2itemplugin_cosmetics.sp::OnStartTouchSpawnRoom
L 09/02/2024 - 03:38:50: [SM] Exception reported: Client index 60 is invalid
L 09/02/2024 - 03:38:50: [SM] Blaming: tf2itemplugin_weapons.smx
L 09/02/2024 - 03:38:50: [SM] Call stack trace:
L 09/02/2024 - 03:38:50: [SM]   [0] IsClientInGame
L 09/02/2024 - 03:38:50: [SM]   [1] Line 65, tf2itemplugin_weapons.sp::OnStartTouchSpawnRoom
L 09/02/2024 - 03:38:50: [SM] Exception reported: Client index 60 is invalid
L 09/02/2024 - 03:38:50: [SM] Blaming: tf2itemplugin_cosmetics.smx
L 09/02/2024 - 03:38:50: [SM] Call stack trace:
L 09/02/2024 - 03:38:50: [SM]   [0] IsClientInGame
L 09/02/2024 - 03:38:50: [SM]   [1] Line 65, tf2itemplugin_cosmetics.sp::OnStartTouchSpawnRoom
L 09/02/2024 - 03:38:50: [SM] Exception reported: Client index 60 is invalid
L 09/02/2024 - 03:38:50: [SM] Blaming: tf2itemplugin_weapons.smx
L 09/02/2024 - 03:38:51: [SM] Call stack trace:
L 09/02/2024 - 03:38:51: [SM]   [0] IsClientInGame
L 09/02/2024 - 03:38:51: [SM]   [1] Line 65, tf2itemplugin_weapons.sp::OnStartTouchSpawnRoom

Fixed SP files :

One bored night later and here's how the code looks, fully functional, no errors and reports to databases correctly.

tf2itemplugin_cosmetics.sp ``` #include "tf2itemplugin/tf2itemplugin_base.sp" #include "tf2itemplugin/tf2itemplugin_cosmetics_base.sp" #include "tf2itemplugin/tf2itemplugin_cosmetics_data.sp" #include "tf2itemplugin/tf2itemplugin_cosmetics_requests.sp" #include "tf2itemplugin/tf2itemplugin_cosmetics_sqlite.sp" #include "tf2itemplugin/tf2itemplugin_cosmetics_menus.sp" #pragma semicolon 1 #pragma newdecls required #define PLUGIN_VERSION "4.0.0" #define DEBUG true public Plugin myinfo = { name = "TF2 Item Plugins - Cosmetics Manager", author = "Lucas 'punteroo' Maza", description = "Customize your cosmetic items and manage your server inventory.", version = PLUGIN_VERSION, url = "https://github.com/punteroo/TF2-Item-Plugins" }; /** * Load the "Regenerate" SDK call to refresh player inventories. * * @return Handle to the "Regenerate" SDK call. */ public Handle TF2ItemPlugin_LoadRegenerateSDK() { // Load TF2 gamedata. Handle hGameConf = LoadGameConfigFile("sm-tf2.games"); // Prepare the SDK call for the player entity. StartPrepSDKCall(SDKCall_Player); // Set the SDK call to find the "Regenerate" signature. PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "Regenerate"); PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); // End the SDK call preparation. return EndPrepSDKCall(); } /** * Uses hooks to attach into the maps' `func_respawnroom` entities to determine if a player is within a spawn room. * * @return void */ public void TF2ItemPlugin_AttachSpawnRoomHooks() { // Declare a starting index for the spawn room entities. int trigger = -1; while ((trigger = FindEntityByClassname(trigger, "func_respawnroom")) != -1) { // Hook callbacks into the trigger. SDKHook(trigger, SDKHook_StartTouch, OnStartTouchSpawnRoom); SDKHook(trigger, SDKHook_EndTouch, OnEndTouchSpawnRoom); } } public Action OnStartTouchSpawnRoom(int entity, int other) { // Check if the entity is a valid client index if (other < 1 || other > MaxClients) return Plugin_Continue; // Is this entity a player? if (!IsClientInGame(other)) return Plugin_Continue; // If player is alive and real, mark them as in spawn room. if (IsPlayerAlive(other) && !IsClientSourceTV(other) && !IsClientObserver(other)) g_bInSpawnRoom[other] = true; return Plugin_Continue; } public Action OnEndTouchSpawnRoom(int entity, int other) { // Check if the entity is a valid client index if (other < 1 || other > MaxClients) return Plugin_Continue; // Is this entity a player? if (!IsClientInGame(other)) return Plugin_Continue; // If player is alive and real, mark them as not in spawn room. if (IsPlayerAlive(other) && !IsClientSourceTV(other) && !IsClientObserver(other)) g_bInSpawnRoom[other] = false; return Plugin_Continue; } public void OnPluginStart() { g_cvar_cosmetics_onlySpawn = CreateConVar("tf2items_cosmetics_spawn_only", "0.0", "If enabled, cosmetic overrides can only be changed in spawn regions.", 0, true, 0.0, true, 1.0); g_cvar_cosmetics_unusualEffectsURL = CreateConVar("tf2items_cosmetics_unusuals_url", "https://raw.githubusercontent.com/punteroo/TF2-Item-Plugins/production/tf2_unusuals.json", "URL from where to fetch the Unusual effects data."); g_cvar_cosmetics_searchTimeout = CreateConVar("tf2items_cosmetics_search_timeout", "15.0", "The amount of time (in seconds) to wait before timing out a player Unusual effect search.", 0, true, 5.0, true, 60.0); g_cvar_cosmetics_databaseCooldown = CreateConVar("tf2items_cosmetics_database_cooldown", "15.0", "The amount of time in seconds to wait before a player can perform a database action. -1 disables the cooldown.", 0, true, -1.0, true, 60.0); // Load the "Regenerate" SDK call. hRegen = TF2ItemPlugin_LoadRegenerateSDK(); // Find the network offsets for the weapon clip and ammo. clipOff = FindSendPropInfo("CTFWeaponBase", "m_iClip1"); ammoOff = FindSendPropInfo("CTFPlayer", "m_iAmmo"); // Register the cosmetic manager commands. static const char commandNames[][24] = { "sm_hats", "sm_hat", "sm_cosmetics", "sm_cosmetic", "sm_myhats" }; for (int i = 0; i < sizeof(commandNames); i++) RegAdminCmd(commandNames[i], CMD_TF2ItemPlugin_CosmeticManager, ADMFLAG_GENERIC, "Manage your cosmetics on the server."); // Connect to the SQlite database. Database.Connect(TF2ItemPlugin_SQL_ConnectToDatabase, "tf2itemplugins_db"); } public void OnClientAuthorized(int client, const char[] auth) { // Initialize the inventory for the client. TF2ItemPlugin_InitializeInventory(client); // Search for the client's preferences. TF2ItemPlugin_SQL_SearchPlayerPreferences(client); // Disable their cooldown flag. g_bIsOnDatabaseCooldown[client] = false; } public void OnMapStart() { // Attach hooks to the spawn room entities. TF2ItemPlugin_AttachSpawnRoomHooks(); // Setup an HTTP request to obtain latest Unusual effects information. char url[512]; g_cvar_cosmetics_unusualEffectsURL.GetString(url, sizeof(url)); LogMessage("Requesting Unusual effects information from %s", url); TF2ItemPlugin_RequestUnusualEffectsData(url); } public Action CMD_TF2ItemPlugin_CosmeticManager(int client, int args) { // If the client is not in a spawn room and the cvar is enabled, notify them. if (!g_bInSpawnRoom[client] && g_cvar_cosmetics_onlySpawn.BoolValue) { CPrintToChat(client, "%s You must be in a spawn room to manage your cosmetic items.", PLUGIN_CHATTAG); return Plugin_Handled; } // Open the cosmetics menu for the client. TF2ItemPlugin_Menus_MainMenu(client); return Plugin_Handled; } ``` ### Changes ```diff - // Is this entity a player? - if (!IsClientInGame(other)) - return Plugin_Continue; - // If player is alive and real, mark them as in spawn room. - if (IsPlayerAlive(other) && !IsClientSourceTV(other) && !IsClientObserver(other) && other <= MaxClients) - g_bInSpawnRoom[GetClientOfUserId(other)] = true; - // Is this entity a player? - if (!IsClientInGame(other)) - return Plugin_Continue; - // If player is alive and real, mark them as not in spawn room. - if (IsPlayerAlive(other) && !IsClientSourceTV(other) && !IsClientObserver(other) && other <= MaxClients) - g_bInSpawnRoom[GetClientOfUserId(other)] = false; - static const char commandNames[][24] = { "sm_hats", "sm_hat", "sm_cosmetics", "sm_cosmetics", "sm_myhats" }; + // Check if the entity is a valid client index + if (other < 1 || other > MaxClients) + return Plugin_Continue; + static const char commandNames[][24] = { "sm_hats", "sm_hat", "sm_cosmetics", "sm_cosmetic", "sm_myhats" }; ```
tf2itemplugin_weapons.sp ``` #include #include #include #include #include #include #include #include "tf2itemplugin/tf2itemplugin_base.sp" #include "tf2itemplugin/tf2itemplugin_weapon_base.sp" #include "tf2itemplugin/tf2itemplugin_weapon_sqlite.sp" #include "tf2itemplugin/tf2itemplugin_weapon_data.sp" #include "tf2itemplugin/tf2itemplugin_weapon_menus.sp" #include "tf2itemplugin/tf2itemplugin_weapon_requests.sp" #pragma semicolon 1 #pragma newdecls required #define PLUGIN_VERSION "4.0.0" #define DEBUG false public Plugin myinfo = { name = "TF2 Item Plugins - Weapons Manager", author = "Lucas 'punteroo' Maza", description = "Customize your weapons and manage your server inventory.", version = PLUGIN_VERSION, url = "https://github.com/punteroo/TF2-Item-Plugins" }; /** * Load the "Regenerate" SDK call to refresh player inventories. * * @return Handle to the "Regenerate" SDK call. */ Handle TF2ItemPlugin_LoadRegenerateSDK() { Handle hGameConf = LoadGameConfigFile("sm-tf2.games"); StartPrepSDKCall(SDKCall_Player); PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "Regenerate"); PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); Handle call = EndPrepSDKCall(); delete hGameConf; return call; } /** * Uses hooks to attach into the maps' `func_respawnroom` entities to determine if a player is within a spawn room. * * @return void */ void TF2ItemPlugin_AttachSpawnRoomHooks() { int trigger = -1; while ((trigger = FindEntityByClassname(trigger, "func_respawnroom")) != -1) { SDKHook(trigger, SDKHook_StartTouch, OnStartTouchSpawnRoom); SDKHook(trigger, SDKHook_EndTouch, OnEndTouchSpawnRoom); } } public Action OnStartTouchSpawnRoom(int entity, int other) { if (IsValidClient(other)) g_bInSpawnRoom[other] = true; return Plugin_Continue; } public Action OnEndTouchSpawnRoom(int entity, int other) { if (IsValidClient(other)) g_bInSpawnRoom[other] = false; return Plugin_Continue; } public void OnPluginStart() { g_cvar_weapons_onlySpawn = CreateConVar("tf2items_weapons_spawnonly", "0", "If enabled, weapon changes are only allowed when the player is within a spawn room.", _, true, 0.0, true, 1.0); g_cvar_weapons_paintKitsUrl = CreateConVar("tf2items_weapons_paintkits_url", "https://raw.githubusercontent.com/punteroo/TF2-Item-Plugins/production/tf2_protos.json", "The URL to the JSON file containing the War Paints and their IDs. Must be a valid JSON array."); g_cvar_weapons_searchTimeout = CreateConVar("tf2items_weapons_search_timeout", "20.0", "The amount of time in seconds to wait for a search to complete before timing out.", _, true, 5.0, true, 60.0); g_cvar_weapons_databaseCooldown = CreateConVar("tf2items_weapons_database_cooldown", "15.0", "The amount of time in seconds to wait before a player can perform a database action. -1 disables the cooldown.", _, true, -1.0); hRegen = TF2ItemPlugin_LoadRegenerateSDK(); clipOff = FindSendPropInfo("CTFWeaponBase", "m_iClip1"); ammoOff = FindSendPropInfo("CTFPlayer", "m_iAmmo"); RegConsoleCmd("sm_weapons", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); RegConsoleCmd("sm_weapon", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); RegConsoleCmd("sm_wep", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); RegConsoleCmd("sm_weps", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); Database.Connect(TF2ItemPlugin_SQL_ConnectToDatabase, "tf2itemplugins_db"); #if defined DEBUG RegAdminCmd("sm_weapons_debug", CMD_TF2ItemPlugin_DebugInventory, ADMFLAG_ROOT, "Print the player's inventory state."); RegAdminCmd("sm_weapons_debug_current", CMD_TF2ItemPlugin_DebugCurrent, ADMFLAG_ROOT, "Print the player's current weapon state."); RegAdminCmd("sm_weapons_debug_force_call", CMD_TF2ItemPlugin_ForceCall, ADMFLAG_ROOT, "Force a call to the Regenerate function."); #endif } public void OnMapStart() { TF2ItemPlugin_AttachSpawnRoomHooks(); char url[512]; g_cvar_weapons_paintKitsUrl.GetString(url, sizeof(url)); LogMessage("Requesting paint kit data from %s", url); TF2ItemPlugin_RequestPaintKitData(url); } public void OnClientAuthorized(int client) { TF2ItemPlugin_InitializeInventory(client); TF2ItemPlugin_SQL_SearchPlayerPreferences(client); g_bIsOnDatabaseCooldown[client] = false; } public Action CMD_TF2ItemPlugin_WeaponManager(int client, int args) { if (!IsValidClient(client)) return Plugin_Handled; if (!g_bInSpawnRoom[client] && g_cvar_weapons_onlySpawn.BoolValue) { CPrintToChat(client, "%s You must be in a spawn room to manage your weapons.", PLUGIN_CHATTAG); return Plugin_Handled; } TF2ItemPlugin_Menus_MainMenu(client); return Plugin_Handled; } #if defined DEBUG void Print_Slot(int client, int class, int slot) { PrintToConsole(client, "Slot %d:\n" ... "Client ID: %d\n" ... "Class ID: %d\n" ... "Slot ID: %d\n" ... "Active Override: %d\n" ... "Weapon Def Index: %d\n" ... "Stock Def Index: %d\n" ... "Quality: %d\n" ... "Level: %d\n" ... "Australium: %d\n" ... "Festive: %d\n" ... "Unusual Effect: %d\n" ... "War Paint ID: %d\n" ... "War Paint Wear: %f\n" ... "- Killstreak:\n" ... " - Active: %d\n" ... " - Tier: %d\n" ... " - Sheen: %d\n" ... " - Killstreaker: %d\n" ... "Spells Bitfield: %d\n" ... "\n\n", slot, g_inventories[client][class][slot].client, g_inventories[client][class][slot].class, g_inventories[client][class][slot].slotId, g_inventories[client][class][slot].isActiveOverride, g_inventories[client][class][slot].weaponDefIndex, g_inventories[client][class][slot].stockWeaponDefIndex, g_inventories[client][class][slot].quality, g_inventories[client][class][slot].level, g_inventories[client][class][slot].isAustralium, g_inventories[client][class][slot].isFestive, g_inventories[client][class][slot].unusualEffectId, g_inventories[client][class][slot].warPaintId, g_inventories[client][class][slot].warPaintWear, g_inventories[client][class][slot].killstreak.isActive, g_inventories[client][class][slot].killstreak.tier, g_inventories[client][class][slot].killstreak.sheen, g_inventories[client][class][slot].killstreak.killstreaker, g_inventories[client][class][slot].halloweenSpell.spells); } public Action CMD_TF2ItemPlugin_DebugInventory(int client, int args) { if (!IsValidClient(client)) return Plugin_Handled; PrintToConsole(client, "Inventory Debug\n\n\n"); if (args >= 1) { char class[2]; GetCmdArg(1, class, sizeof(class)); int iclass = StringToInt(class); if (args >= 2) { char slot[2]; GetCmdArg(2, slot, sizeof(slot)); int islot = StringToInt(slot); PrintToConsole(client, "For class %d, slot %d\n", iclass, islot); Print_Slot(client, iclass, islot); return Plugin_Handled; } PrintToConsole(client, "For class %d\n", iclass); for (int j = 0; j < MAX_WEAPONS; j++) Print_Slot(client, iclass, j); return Plugin_Handled; } for (int i = 0; i < MAX_CLASSES; i++) { PrintToConsole(client, "For class %d\n", i); for (int j = 0; j < MAX_WEAPONS; j++) { Print_Slot(client, i, j); } } return Plugin_Handled; } public Action CMD_TF2ItemPlugin_DebugCurrent(int client, int args) { if (!IsValidClient(client)) return Plugin_Handled; int weapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon"); if (!IsValidEntity(weapon)) { PrintToConsole(client, "No weapon found."); return Plugin_Handled; } int defIndex = GetEntProp(weapon, Prop_Send, "m_iItemDefinitionIndex"); int indexes[16]; float values[16]; TF2Attrib_GetSOCAttribs(weapon, indexes, values); PrintToConsole(client, "Current Weapon: %d\n" ... "Item Definition Index: %d\n\n", weapon, defIndex); PrintToConsole(client, "SOC Attributes\n\n"); for (int i = 0; i < 16; i++) { if (indexes[i] == 0) break; PrintToConsole(client, "SOC Attribute %d: %d = %f", i, indexes[i], values[i]); } PrintToConsole(client, "Attributes\n\n"); int attributes[16]; int count = TF2Attrib_ListDefIndices(weapon, attributes); for (int i = 0; i < count; i++) { if (attributes[i] == 0) continue; Address attrib = TF2Attrib_GetByDefIndex(weapon, attributes[i]); float value = TF2Attrib_GetValue(attrib); PrintToConsole(client, "Attribute %d: %d = %f", i, attributes[i], value); } return Plugin_Handled; } public Action CMD_TF2ItemPlugin_ForceCall(int client, int args) { if (!IsValidClient(client)) return Plugin_Handled; SDKCall(hRegen, client, false); return Plugin_Handled; } #endif bool IsValidClient(int client) { return (client > 0 && client <= MaxClients && IsClientInGame(client) && !IsClientSourceTV(client) && !IsClientReplay(client)); } ``` ### Changes ```diff -#define PLUGIN_VERSION "3.1.0" + #define PLUGIN_VERSION "4.0.0" -void TF2ItemPlugin_LoadConfig() -{ - g_cvar_affected_weapons_onlySpawn = CreateConVar("tf2items_affected_weapons_only_spawn", "0", "If enabled, weapon changes are only allowed when the player is within a spawn room.", _, true, 0.0, true, 1.0); - g_cvar_affected_weapons_paintKitsUrl = CreateConVar("tf2items_affected_weapons_paintkits_url", "https://raw.githubusercontent.com/punteroo/TF2-Item-Plugins/production/tf2_protos.json", "The URL to the JSON file containing the War Paints and their IDs. Must be a valid JSON array."); - g_cvar_affected_weapons_searchTimeout = CreateConVar("tf2items_affected_weapons_search_timeout", "20.0", "The amount of time in seconds to wait for a search to complete before timing out.", _, true, 5.0, true, 60.0); - g_cvar_affected_weapons_databaseCooldown = CreateConVar("tf2items_affected_weapons_database_cooldown", "15.0", "The amount of time in seconds to wait before a player can perform a database action. -1 disables the cooldown.", _, true, -1.0); -} + Handle TF2ItemPlugin_LoadRegenerateSDK() +{ + Handle hGameConf = LoadGameConfigFile("sm-tf2.games"); + + StartPrepSDKCall(SDKCall_Player); + PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "Regenerate"); + PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); + + Handle call = EndPrepSDKCall(); + delete hGameConf; + return call; +} -void TF2ItemPlugin_LoadConfig() +void TF2ItemPlugin_AttachSpawnRoomHooks() +{ + int trigger = -1; + while ((trigger = FindEntityByClassname(trigger, "func_respawnroom")) != -1) + { + SDKHook(trigger, SDKHook_StartTouch, OnStartTouchSpawnRoom); + SDKHook(trigger, SDKHook_EndTouch, OnEndTouchSpawnRoom); + } +} -void TF2ItemPlugin_LoadConfig() + g_cvar_weapons_onlySpawn = CreateConVar("tf2items_weapons_spawnonly", "0", "If enabled, weapon changes are only allowed when the player is within a spawn room.", _, true, 0.0, true, 1.0); + g_cvar_weapons_paintKitsUrl = CreateConVar("tf2items_weapons_paintkits_url", "https://raw.githubusercontent.com/punteroo/TF2-Item-Plugins/production/tf2_protos.json", "The URL to the JSON file containing the War Paints and their IDs. Must be a valid JSON array."); + g_cvar_weapons_searchTimeout = CreateConVar("tf2items_weapons_search_timeout", "20.0", "The amount of time in seconds to wait for a search to complete before timing out.", _, true, 5.0, true, 60.0); + g_cvar_weapons_databaseCooldown = CreateConVar("tf2items_weapons_database_cooldown", "15.0", "The amount of time in seconds to wait before a player can perform a database action. -1 disables the cooldown.", _, true, -1.0); + hRegen = TF2ItemPlugin_LoadRegenerateSDK(); + clipOff = FindSendPropInfo("CTFWeaponBase", "m_iClip1"); + ammoOff = FindSendPropInfo("CTFPlayer", "m_iAmmo"); - RegConsoleCmd("sm_weapons", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); - RegConsoleCmd("sm_weapon", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); - RegConsoleCmd("sm_wep", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); - RegConsoleCmd("sm_weps", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); + RegConsoleCmd("sm_weapons", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); + RegConsoleCmd("sm_weapon", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); + RegConsoleCmd("sm_wep", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); + RegConsoleCmd("sm_weps", CMD_TF2ItemPlugin_WeaponManager, "Manage weapons on the server."); - Database.Connect(TF2ItemPlugin_SQL_ConnectToDatabase, "tf2itemplugins_db"); + Database.Connect(TF2ItemPlugin_SQL_ConnectToDatabase, "tf2itemplugins_db"); #if defined DEBUG - RegAdminCmd("sm_weapons_debug", CMD_TF2ItemPlugin_DebugInventory, ADMFLAG_ROOT, "Print the player's inventory state."); - RegAdminCmd("sm_weapons_debug_current", CMD_TF2ItemPlugin_DebugCurrent, ADMFLAG_ROOT, "Print the player's current weapon state."); - RegAdminCmd("sm_weapons_debug_force_call", CMD_TF2ItemPlugin_ForceCall, ADMFLAG_ROOT, "Force a call to the Regenerate function."); + RegAdminCmd("sm_weapons_debug", CMD_TF2ItemPlugin_DebugInventory, ADMFLAG_ROOT, "Print the player's inventory state."); + RegAdminCmd("sm_weapons_debug_current", CMD_TF2ItemPlugin_DebugCurrent, ADMFLAG_ROOT, "Print the player's current weapon state."); + RegAdminCmd("sm_weapons_debug_force_call", CMD_TF2ItemPlugin_ForceCall, ADMFLAG_ROOT, "Force a call to the Regenerate function."); +bool IsValidClient(int client) +{ + return (client > 0 && client <= MaxClients && IsClientInGame(client) && !IsClientSourceTV(client) && !IsClientReplay(client)); +} ```

Alternatively, here's the compiled version

punteroo commented 2 months ago

Reopening as this is a known issue and will be fixed officially once I'm able to.

Thanks in advance for providing a fix for it, I recommend you create a pull request so I can review and merge your fixes accordingly 👍.

punteroo commented 2 months ago

34 merged.

Closing.