Raised This Month: $32 Target: $400
 8% 

Solved [TF2] Client game crash when the client get a weapon


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Whai
Senior Member
Join Date: Jul 2018
Old 11-12-2019 , 18:54   [TF2] Client game crash when the client get a weapon
Reply With Quote #1

The client game crash (so not the server) when he is given a weapon

Here is a part of the code

PHP Code:
bool TF2_GivePlayerItem(int iClientint iTargetint iItemID)
{
    if(!
TF2IDB_IsValidItemID(iItemID))
    {
        
PrintToChat(iClient"[SM] Invalid item definition index");
        return 
false;
    }
    
    
char strClassname[TF2IDB_ITEMCLASS_LENGTH];
    
TF2IDB_GetItemClass(iItemIDstrClassnamesizeof(strClassname));

    
int iSlot view_as<int>(TF2IDB_GetItemSlot(iItemID));
    
int iQuality view_as<int>(TF2IDB_GetItemQuality(iItemID));

    
int iMinLeveliMaxLevel 127// 127 is from tf2items.inc
    
TF2IDB_GetItemLevels(iItemIDiMinLeveliMaxLevel);
        
    
    
int iAttributeID[15]; // max number of attribute tf2 can hold
    
float flAttributeValue[15];
    
    
int iNumAttribute TF2IDB_GetItemAttributes(iItemIDiAttributeIDflAttributeValue);
    
    
#if DEBUG
        
PrintToServer("strClassname : %s"strClassname);
        
PrintToServer("iSlot : %i"iSlot);
        
PrintToServer("iQuality : %i"iQuality);
        
PrintToServer("iMinLevel : %i"iMinLevel);
        
PrintToServer("iMaxLevel : %i"iMaxLevel);
        
PrintToServer("iNumAttribute : %i"iNumAttribute);
    
#endif
    
    
Handle hItem TF2Items_CreateItem(OVERRIDE_ALL FORCE_GENERATION);
    
TF2Items_SetItemIndex(hItemiItemID);
    
TF2Items_SetClassname(hItemstrClassname);
    
TF2Items_SetQuality(hItemiQuality);
    
TF2Items_SetLevel(hItemGetRandomInt(iMinLeveliMaxLevel));
    
    
TF2Items_SetNumAttributes(hItemiNumAttribute);
    for(
int iiNumAttributei++)
        
TF2Items_SetAttribute(hItemiiAttributeID[i], flAttributeValue[i]);
    
    if(
iSlot 5// from 0 to 4 --> weapon slots
    
{
        
int iEntityiEntityIndexDefinition;
        while((
iEntity FindEntityByClassname(iEntity"tf_wearable*")) != INVALID_ENT_REFERENCE)
        {
            if(
iTarget != GetEntPropEnt(iEntityProp_Send"m_hOwnerEntity")) continue;
            
            
iEntityIndexDefinition GetEntProp(iEntityProp_Send"m_iItemDefinitionIndex");
            if(
view_as<int>(TF2IDB_GetItemSlot(iEntityIndexDefinition)) != iSlot) continue;
            
            
TF2_RemoveWearable(iTargetiEntity);
            break;
        }
    }
    
    if(
iSlot 5)
        
TF2_RemoveWeaponSlot(iTargetiSlot);
    
    
int iItem TF2Items_GiveNamedItem(iTargethItem);
    if(
IsValidEntity(iItem))
    {
        if(
IsWearable(iItem))    //TODO: Thinking about if the new item equip region conflicts with an item of the target to remove it and replace it by the new item
            
EquipPlayerWearable(iTargetiItem);
            
        else
            
EquipPlayerWeapon(iTargetiItem);
    }
        
    
CloseHandle(hItem);
    
hItem INVALID_HANDLE;
    
    return 
true;
}

void EquipPlayerWearable(int iClientint iEntity)
{
    if(!
IsWearable(iEntity)) 
        return;
    
    
SDKCall(g_hEquipWearableiClientiEntity);
}

bool IsWearable(int iEntity)
{
    return 
SDKCall(g_hIsWearableiEntity);


Note: When I remove the "EquipPlayerWeapon", the client game doesn't crash

Note2; For some reason, when the active weapon of the client is not in the same slot of the new item, the game doesn't crash


SOLUTION
__________________

Last edited by Whai; 11-20-2019 at 18:07. Reason: solved
Whai is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 11-15-2019 , 13:31   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #2

Here's the stock I use to force a weapon slot switch. Maybe you could force a weapon slot change before you equip the new weapon.

If I may ask... What are you trying to build? There are plugins that turn players into a giant robot with specific weapons and attributes.

Code:
stock TF2_SwitchtoSlot(client, slot)
{
	if (slot >= 0 && slot <= 5 && IsClientInGame(client) && IsPlayerAlive(client))
	{
		new String:wepclassname[64];
		new wep = GetPlayerWeaponSlot(client, slot);
		if (wep > MaxClients && IsValidEdict(wep) && GetEdictClassname(wep, wepclassname, sizeof(wepclassname)))
		{
			FakeClientCommandEx(client, "use %s", wepclassname);
			SetEntPropEnt(client, Prop_Send, "m_hActiveWeapon", wep);
		}
	}
}
PC Gamer is offline
Whai
Senior Member
Join Date: Jul 2018
Old 11-15-2019 , 16:24   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #3

Quote:
Originally Posted by PC Gamer View Post
Here's the stock I use to force a weapon slot switch. Maybe you could force a weapon slot change before you equip the new weapon.
It still crashing, I added this function right before the EquipPlayerWeapon()
Code:
TF2_SwitchtoSlot(iTarget, (!iSlot ? 2 : 0));
The game doesn't crash instantly but crashes when I switch to the new weapon (for some reason, sometimes, it doesn't crash)

Quote:
Originally Posted by PC Gamer View Post
If I may ask... What are you trying to build? There are plugins that turn players into a giant robot with specific weapons and attributes.
Just a plugin that gives item by the item definition index
__________________
Whai is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 11-18-2019 , 09:16   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #4

I managed to get this working with the [TF2] Econ Data plugin written by the talented nosoop (link:https://forums.alliedmods.net/showthread.php?t=315011 )

It works good but has a 3 problems I need help with.

1. I have a tag mismatch with this piece of code:
Quote:
int iTargetClassType = view_as<int>(TF2_GetPlayerClass(iTarget));
int iSlot = TF2Econ_GetItemSlot(iItemID, iTargetClassType); //I get a tag mismatch warning on this line
2: I can't seem to find a way to remove only ONE existing cosmetic item before giving a new one. I can either remove all cosmetics first, or don't remove any. I opted to not remove any.

3. For some reason it will not allow me to give any saxxy class item. It gives error "Invalid entity (-1 - -1)" so I added a check for that.

PHP Code:
#include <tf2attributes>
#include <tf_econ_data>

#pragma semicolon 1

#define DEBUG 0
#define PLUGIN_VERSION "1.0"

Handle g_hWeaponEquip;
Handle g_hWWeaponEquip;
Handle g_hIsWearable;
Handle g_hGameConfig;

public 
Plugin myinfo 
{
    
name "Give Stuff",
    
author "Whai and PC Gamer",
    
description "Give Weapon and Cosmetic items to players",
    
version PLUGIN_VERSION,
    
url "https://forums.alliedmods.net"
}

public 
void OnPluginStart() 
{
    
g_hGameConfig LoadGameConfigFile("give.stuff");
    
    if (!
g_hGameConfig)
    {
        
SetFailState("Failed to find give.stuff.txt gamedata! Can't continue.");
    }    
    
    
StartPrepSDKCall(SDKCall_Player);
    
PrepSDKCall_SetFromConf(g_hGameConfigSDKConf_Virtual"WeaponEquip");
    
PrepSDKCall_AddParameter(SDKType_CBaseEntitySDKPass_Pointer);
    
g_hWeaponEquip EndPrepSDKCall();
    
    if (!
g_hWeaponEquip)
    {
        
SetFailState("Failed to prepare the SDKCall for giving weapons. Try updating gamedata or restarting your server.");
    }
    
    
StartPrepSDKCall(SDKCall_Player);
    
PrepSDKCall_SetFromConf(g_hGameConfigSDKConf_Virtual"EquipWearable");
    
PrepSDKCall_AddParameter(SDKType_CBaseEntitySDKPass_Pointer);
    
g_hWWeaponEquip EndPrepSDKCall();
    
    if (!
g_hWWeaponEquip)
    {
        
SetFailState("Failed to prepare the SDKCall for giving wearable weapons. Try updating gamedata or restarting your server.");
    }
    
    
StartPrepSDKCall(SDKCall_Player);
    
PrepSDKCall_SetFromConf(g_hGameConfigSDKConf_Virtual"IsWearable");
    
PrepSDKCall_AddParameter(SDKType_CBaseEntitySDKPass_Pointer);
    
g_hIsWearable EndPrepSDKCall();
    
    if (!
g_hIsWearable)
    {
        
SetFailState("Failed to prepare the SDKCall for Determining if item is wearable. Try updating gamedata or restarting your server.");
    }    
    
    
RegAdminCmd("sm_give"Command_GiveADMFLAG_SLAY"Have a Great Day!");    
}

public 
Action:Command_Give(clientargs)
{
    if (
args != 2)
    {
        
ReplyToCommand(client"[SM] Usage: sm_give <client> <index>");
        return 
Plugin_Handled;
    }
    
    new 
String:arg1[32];
    
GetCmdArg(1arg1sizeof(arg1));
    
    new 
String:arg2[32];
    
GetCmdArg(2arg2sizeof(arg2));

    
decl String:target_name[MAX_TARGET_LENGTH];
    
decl target_list[MAXPLAYERS], target_countbool:tn_is_ml;
    
    if ((
target_count ProcessTargetString(
                    
arg1,
                    
client,
                    
target_list,
                    
MAXPLAYERS,
                    
COMMAND_FILTER_CONNECTED,
                    
target_name,
                    
sizeof(target_name),
                    
tn_is_ml)) <= 0)
    {
        
ReplyToTargetError(clienttarget_count);
        return 
Plugin_Handled;
    }
    
    new 
itemID StringToInt(arg2);

    for (new 
0target_counti++)
    {
        
TF2_GivePlayerItem(clienttarget_list[i], itemID);        
    }
    
    return 
Plugin_Handled;
}

public 
Action:TF2_GivePlayerItem(int iClientint iTargetint iItemID)
{
    if (!(
IsValidClient(iTarget) || IsPlayerAlive(iTarget)))
    {
        
PrintToChat(iClient"Target is Not Alive");
        return 
Plugin_Handled;
    }
    
    if(!
TF2Econ_IsValidItemDefinition(iItemID))
    {
        
PrintToChat(iClient"[SM] Invalid item definition index");
        return 
Plugin_Handled;
    }

    
int iLevel GetRandomInt(1,99);
    
int iQuality GetRandomInt(0,14);

    
char strClassname[32];
    
TF2Econ_GetItemClassName(iItemIDstrClassnamesizeof(strClassname));
    
int weaponprimary CreateEntityByName(strClassname);
    if (!
IsValidEntity(weaponprimary))
    {
        
PrintToChat(iClient,"Invalid Entity: Item Classname : %s"strClassname);    
        return 
Plugin_Handled;
    }

    
char entclass[64];
    
GetEntityNetClass(weaponprimaryentclasssizeof(entclass));
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iItemDefinitionIndex"), iItemID);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_bInitialized"), 1);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iEntityLevel"), iLevel);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iEntityQuality"), iQuality);
    
TF2Attrib_SetByDefIndex(weaponprimary7250.2);
    
    
int iTargetClassType view_as<int>(TF2_GetPlayerClass(iTarget));
    
int iSlot TF2Econ_GetItemSlot(iItemIDiTargetClassType);  //I get a tag mismatch warning on this line
    
if (iSlot <0)
    {
        
PrintToChat(iClient"Item Index %i is invalid for target class"iItemID);
        return 
Plugin_Handled;
    }

    if (
iSlot >6)
    {
        
//        TF2_RemoveAllWearables(iTarget);
        
        
DispatchSpawn(weaponprimary);
        
SDKCall(g_hWWeaponEquipiTargetweaponprimary);
    }
    else
    {
        
TF2_RemoveWeaponSlot(iTargetiSlot);
        
DispatchSpawn(weaponprimary);
        
SDKCall(g_hWeaponEquipiTargetweaponprimary);
    }
    
    
char strItemName[64];
    
TF2Econ_GetItemName(iItemIDstrItemNamesizeof(strItemName));
    
PrintToChat(iClient"Gave %s to %N"strItemNameiTarget);    
    
    
#if DEBUG
    
char strQualityName[32];
    
TF2Econ_GetQualityName(iQualitystrQualityNamesizeof(strQualityName));

    
char strItemSlotName[32];
    
TF2Econ_TranslateLoadoutSlotIndexToName(iSlotstrItemSlotNamesizeof(strItemSlotName));

    
PrintToChat(iClient,"[Give Debug]: Item Name : %s"strItemName);
    
PrintToChat(iClient,"[Give Debug]: Item Classname : %s"strClassname);
    
PrintToChat(iClient,"[Give Debug]: iSlot : %i"iSlot);
    
PrintToChat(iClient,"[Give Debug]: iSlotName : %s"strItemSlotName);    
    
PrintToChat(iClient,"[Give Debug]: iQuality : %i"iQuality);
    
PrintToChat(iClient,"[Give Debug]: iQualityName : %s"strQualityName);    
    
PrintToChat(iClient,"[Give Debug]: iLevel : %i"iLevel);

    
#endif

    
return Plugin_Handled;
}

stock bool:IsValidClient(client)
{
    if (
client <= 0) return false;
    if (
client MaxClients) return false;
    return 
IsClientInGame(client);
}

stock TF2_RemoveAllWearables(client)
{
    
RemoveWearable(client"tf_wearable""CTFWearable");
    
RemoveWearable(client"tf_powerup_bottle""CTFPowerupBottle");
}

stock RemoveWearable(clientString:classname[], String:networkclass[])
{
    if (
IsValidClient(client) && IsPlayerAlive(client))
    {
        new 
edict MaxClients+1;
        while((
edict FindEntityByClassname(edictclassname)) != -1)
        {
            
decl String:netclass[32];
            if (
GetEntityNetClass(edictnetclasssizeof(netclass)) && StrEqual(netclassnetworkclass))
            {
                if (
GetEntPropEnt(edictProp_Send"m_hOwnerEntity") == client)
                {
                    
AcceptEntityInput(edict"Kill"); 
                }
            }
        }
    }

Attached Files
File Type: txt give.stuff.txt (349 Bytes, 56 views)
File Type: sp Get Plugin or Get Source (give.sp - 53 views - 6.1 KB)
PC Gamer is offline
nosoop
Veteran Member
Join Date: Aug 2014
Old 11-18-2019 , 11:18   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #5

Quote:
Originally Posted by PC Gamer View Post
I managed to get this working with the [TF2] Econ Data plugin written by the talented nosoop (link:https://forums.alliedmods.net/showthread.php?t=315011 )

It works good but has a 3 problems I need help with.

1. I have a tag mismatch with this piece of code:

2: I can't seem to find a way to remove only ONE existing cosmetic item before giving a new one. I can either remove all cosmetics first, or don't remove any. I opted to not remove any.

3. For some reason it will not allow me to give any saxxy class item. It gives error "Invalid entity (-1 - -1)" so I added a check for that.
1. The second argument to TF2Econ_GetItemSlot is already a TFClassType tag; keep it as-is instead of retagging it as an integer. On an additional note, do not use TF2_RemoveWeaponSlot with TF2Econ_GetItemSlot due to the differing "slot" mapping described here. Use TF2_GetPlayerLoadoutSlot from my fork of Powerlord's wearable tools or check the item's loadout slot with TF2Econ_GetItemSlot.

2. As in (1), use TF2_GetPlayerLoadoutSlot to find a wearable in a weapon slot. The wearable tools library also has natives to equip / remove wearables.

3. That's a game thing -- it internally takes the schema's item class and turns it into a class-appropriate entity (multiclass melees and shotguns, among others). Econ Data provides TF2Econ_TranslateWeaponEntForClass (calling the game's functions) for this; I know there's a pure SourcePawn version that someone else wrote floating around somewhere but I can't recall where it is at the moment.
__________________
I do TF2, TF2 servers, and TF2 plugins.
I don't do DMs over Discord -- PM me on the forums regarding inquiries.
AlliedModders Releases / Github / TF2 Server / Donate (BTC / BCH / coffee)
nosoop is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 11-18-2019 , 18:35   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #6

Thanks again nosoop! With your help I managed to eliminate tag mismatch error.

Good News: It now runs without any crashes.
Bad News: I had to add an include for tf2items_giveweapon exclusively for wearable items in weapon slots (razorback, tide turner, etc.).

I'd like to remove the dependency on tf2items if at all possible. However, after trying for several hours and many server crashes I still couldn't figure out how to use the forked version of tf2wearables and Econ Data to do this:
1. remove whatever weapon is in slot 1, and
2. replace it with a wearable weapon such as the razorback.

On the plus side, after reading your notes above I was able to come up with a better (but not perfect) way to solve the slot problems with removeslot.

If you have a way to remove the dependency on tf2items_giveweapon please share. I'm eager to learn.

This code relies on forked version of tf2wearables mentioned above, tf2items_giveweapon, and tf2attributes. It's functional but could be improved.

PHP Code:
#include <tf2attributes>
#include <tf_econ_data>
#include <tf2wearables>
#include <tf2items_giveweapon>

#pragma semicolon 1

#define DEBUG 0
#define PLUGIN_VERSION "1.1"

Handle g_hWeaponEquip;
Handle g_hWWeaponEquip;
Handle g_hGameConfig;

public 
Plugin myinfo 
{
    
name "Give Stuff",
    
author "Whai and PC Gamer",
    
description "Give Weapon and Cosmetic items to players",
    
version PLUGIN_VERSION,
    
url "https://forums.alliedmods.net"
}

public 
void OnPluginStart() 
{
    
g_hGameConfig LoadGameConfigFile("give.stuff");
    
    if (!
g_hGameConfig)
    {
        
SetFailState("Failed to find give.stuff.txt gamedata! Can't continue.");
    }    
    
    
StartPrepSDKCall(SDKCall_Player);
    
PrepSDKCall_SetFromConf(g_hGameConfigSDKConf_Virtual"WeaponEquip");
    
PrepSDKCall_AddParameter(SDKType_CBaseEntitySDKPass_Pointer);
    
g_hWeaponEquip EndPrepSDKCall();
    
    if (!
g_hWeaponEquip)
    {
        
SetFailState("Failed to prepare the SDKCall for giving weapons. Try updating gamedata or restarting your server.");
    }
    
    
StartPrepSDKCall(SDKCall_Player);
    
PrepSDKCall_SetFromConf(g_hGameConfigSDKConf_Virtual"EquipWearable");
    
PrepSDKCall_AddParameter(SDKType_CBaseEntitySDKPass_Pointer);
    
g_hWWeaponEquip EndPrepSDKCall();
    
    if (!
g_hWWeaponEquip)
    {
        
SetFailState("Failed to prepare the SDKCall for giving wearable weapons. Try updating gamedata or restarting your server.");
    }
    
    
RegAdminCmd("sm_give"Command_GiveADMFLAG_SLAY"Have a Great Day!");    
}

public 
Action:Command_Give(clientargs)
{
    if (
args != 2)
    {
        
ReplyToCommand(client"[SM] Usage: sm_give <client> <index>");
        return 
Plugin_Handled;
    }
    
    new 
String:arg1[32];
    
GetCmdArg(1arg1sizeof(arg1));
    
    new 
String:arg2[32];
    
GetCmdArg(2arg2sizeof(arg2));

    
decl String:target_name[MAX_TARGET_LENGTH];
    
decl target_list[MAXPLAYERS], target_countbool:tn_is_ml;
    
    if ((
target_count ProcessTargetString(
                    
arg1,
                    
client,
                    
target_list,
                    
MAXPLAYERS,
                    
COMMAND_FILTER_CONNECTED,
                    
target_name,
                    
sizeof(target_name),
                    
tn_is_ml)) <= 0)
    {
        
ReplyToTargetError(clienttarget_count);
        return 
Plugin_Handled;
    }
    
    new 
itemID StringToInt(arg2);

    for (new 
0target_counti++)
    {
        
TF2_GivePlayerItem(clienttarget_list[i], itemID);        
    }
    
    return 
Plugin_Handled;
}

public 
Action:TF2_GivePlayerItem(int iClientint iTargetint iItemID)
{
    if (!(
IsValidClient(iTarget) || IsPlayerAlive(iTarget)))
    {
        
PrintToChat(iClient"Target is Not Alive");
        return 
Plugin_Handled;
    }
    
    if(!
TF2Econ_IsValidItemDefinition(iItemID))
    {
        
PrintToChat(iClient"[SM] Invalid item definition index");
        return 
Plugin_Handled;
    }
    if (
iItemID == 405 || iItemID == 608 || iItemID == 1101 || iItemID == 133 || iItemID == 444 || iItemID == 57 || iItemID == 231 || iItemID == 642 || iItemID == 131 || iItemID == 406 || iItemID == 1099 || iItemID == 1144)
    {
        
TF2_RemoveWeaponSlot(iTarget1);
        
TF2Items_GiveWeapon(iTargetiItemID);
        
PrintToChat(iClient"Gave Item %i to %N"iItemIDiTarget);
        
PrintToChat(iTarget"%N Gave You Item %i"iClientiItemID);
        return 
Plugin_Handled;
    }

    
int iLevel GetRandomInt(1,99);
    
int iQuality GetRandomInt(0,14);

    
char strClassname[64];
    
TF2Econ_GetItemClassName(iItemIDstrClassnamesizeof(strClassname));
    
#if DEBUG
    
PrintToChat(iClient"Old Item Name: %s"strClassname);    
    
#endif    
    
TF2Econ_TranslateWeaponEntForClass(strClassnamesizeof(strClassname), TF2_GetPlayerClass(iTarget));
    
#if DEBUG
    
PrintToChat(iClient"New Item Translated Name: %s"strClassname);
    
#endif
    
int weaponprimary CreateEntityByName(strClassname);

    if (!
IsValidEntity(weaponprimary))
    {
        
PrintToChat(iClient,"Invalid Entity: Item Classname : %s"strClassname);    
        return 
Plugin_Handled;
    }

    
char entclass[64];
    
GetEntityNetClass(weaponprimaryentclasssizeof(entclass));
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iItemDefinitionIndex"), iItemID);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_bInitialized"), 1);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iEntityLevel"), iLevel);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iEntityQuality"), iQuality);
    
TF2Attrib_SetByDefIndex(weaponprimary7250.2);

    new 
iSlot TF2Econ_GetItemSlot(iItemIDTF2_GetPlayerClass(iTarget)); 

    
TF2Econ_TranslateWeaponEntForClass(strClassnamesizeof(strClassname), TF2_GetPlayerClass(iTarget));
    if (
StrEqual(strClassname"tf_weapon_revolver"false))
    {
        
iSlot 0;
    }
    if (
StrEqual(strClassname"tf_weapon_knife"false))
    {
        
iSlot 2;
    }
    if (
StrEqual(strClassname"tf_weapon_pda_spy"false))
    {
        
iSlot 3;
    }
    if (
StrEqual(strClassname"tf_weapon_invis"false))
    {
        
iSlot 4;
    }    
    
    switch (
iItemID)
    {
    case 
81083193310801102:
        {
            
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iObjectType"), 3);
            
iSlot 0;
        }
    case 
25737:
        {
            
iSlot 3;
        }
    case 
998:
        {
            
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_nChargeResistType"), GetRandomInt(0,2));
        }
    case 
1071:
        {
            
TF2Attrib_SetByName(weaponprimary"item style override"0.0);
            
TF2Attrib_SetByName(weaponprimary"loot rarity"1.0);        
            
TF2Attrib_SetByName(weaponprimary"turn to gold"1.0);
        }        
    }
    
    if (
iSlot <0)
    {
        
PrintToChat(iClient"Item Index %i is invalid for target class"iItemID);
        return 
Plugin_Handled;
    }

    if (
iSlot >6)
    {
        
DispatchSpawn(weaponprimary);
        
SDKCall(g_hWWeaponEquipiTargetweaponprimary);
    }
    else
    {
        
TF2_RemoveWeaponSlot(iTargetiSlot);
        
DispatchSpawn(weaponprimary);
        
SDKCall(g_hWeaponEquipiTargetweaponprimary);
    }
    
    
char strItemName[64];
    
TF2Econ_GetItemName(iItemIDstrItemNamesizeof(strItemName));
    
PrintToChat(iClient"Gave %s to %N"strItemNameiTarget);    
    
PrintToChat(iTarget"%N gave you a %s"iClientstrItemName);
    
    
#if DEBUG
    
char strQualityName[32];
    
TF2Econ_GetQualityName(iQualitystrQualityNamesizeof(strQualityName));

    
char strItemSlotName[32];
    
TF2Econ_TranslateLoadoutSlotIndexToName(iSlotstrItemSlotNamesizeof(strItemSlotName));

    
PrintToChat(iClient"[Give Debug]: Target Name : %N"iTarget);
    
PrintToChat(iClient"[Give Debug]: Target Class : %i"TF2_GetPlayerClass(iTarget));
    
PrintToChat(iClient"[Give Debug]: Item Name : %s"strItemName);
    
PrintToChat(iClient"[Give Debug]: Item Classname : %s"strClassname);
    
PrintToChat(iClient"[Give Debug]: iSlot : %i"iSlot);
    
PrintToChat(iClient"[Give Debug]: iSlotName : %s"strItemSlotName);    
    
PrintToChat(iClient"[Give Debug]: iQuality : %i"iQuality);
    
PrintToChat(iClient"[Give Debug]: iQualityName : %s"strQualityName);    
    
PrintToChat(iClient"[Give Debug]: iLevel : %i"iLevel);

    
#endif

    
return Plugin_Handled;
}

stock bool:IsValidClient(client)
{
    if (
client <= 0) return false;
    if (
client MaxClients) return false;
    return 
IsClientInGame(client);


Last edited by PC Gamer; 11-18-2019 at 18:36.
PC Gamer is offline
nosoop
Veteran Member
Join Date: Aug 2014
Old 11-18-2019 , 19:13   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #7

For wearables you can create them as you would weapons, but then use TF2_EquipPlayerWearable from tf2wearables instead of your WeaponEquip SDKCall (or EquipPlayerWeapon native call).

To get the player's existing item for removal, use TF2_GetPlayerLoadoutSlot, passing the loadout slot value from TF2Econ_GetItemSlot as the slot argument. Check the item with TF2_IsWearable then call TF2_RemoveWearable or TF2_RemoveWeapon as appropriate.
__________________
I do TF2, TF2 servers, and TF2 plugins.
I don't do DMs over Discord -- PM me on the forums regarding inquiries.
AlliedModders Releases / Github / TF2 Server / Donate (BTC / BCH / coffee)
nosoop is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 11-20-2019 , 02:41   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #8

Thanks again nosoop! With your sage advice I was able to get much farther.

Good News: Removed dependency of tf2items_giveweapon
Bad News: I'm still having a problem determining the correct slot to remove an existing wearable item.

I think maybe there is a problem with TF2_GetPlayerLoadoutSlot incorrectly because it always returns slot 8 for any wearable. I tested this with the tf2wearables_test plugin and found similar result. In other words, when I have three wearable items equipped the 'checkmyitems' command will only show one wearable in slot 8.

The impact is that it when I try to remove an item it will usually remove the wrong item.

Any idea on what I can do to fix the problem?

Output from tf2wearables_test plugin:
Quote:
Processed items for PC Gamer
PC Gamer Item Slot 0: ent 570, class "tf_weapon_handgun_scout_primary", index 220
PC Gamer Item Slot 1: ent 571, class "tf_weapon_pistol_scout", index 30666
PC Gamer Item Slot 2: ent 320, class "tf_weapon_bat", index 452
PC Gamer Item Slot 8: ent 490, class "tf_wearable", index 30253
PC Gamer Item Slot 9: ent 600, class "tf_weapon_spellbook", index 1132
Code with the changes you recommended:
PHP Code:
#include <tf2attributes>
#include <tf_econ_data>
#include <tf2wearables>

#pragma semicolon 1

#define DEBUG 1
#define PLUGIN_VERSION "1.3"

public Plugin myinfo 
{
    
name "Give Stuff",
    
author "Whai and PC Gamer",
    
description "Give Weapon and Cosmetic items to players",
    
version PLUGIN_VERSION,
    
url "https://forums.alliedmods.net"
}

public 
void OnPluginStart() 
{
    
RegAdminCmd("sm_give"Command_GiveADMFLAG_SLAY"Give Others an Item");
    
RegConsoleCmd("sm_get"Command_Get"Give Self an Item");    
}

public 
Action:Command_Give(clientargs)
{
    if (
args != 2)
    {
        
ReplyToCommand(client"[SM] Usage: sm_give <client> <index>");
        return 
Plugin_Handled;
    }
    
    new 
String:arg1[32];
    
GetCmdArg(1arg1sizeof(arg1));
    
    new 
String:arg2[32];
    
GetCmdArg(2arg2sizeof(arg2));

    
decl String:target_name[MAX_TARGET_LENGTH];
    
decl target_list[MAXPLAYERS], target_countbool:tn_is_ml;
    
    if ((
target_count ProcessTargetString(
                    
arg1,
                    
client,
                    
target_list,
                    
MAXPLAYERS,
                    
COMMAND_FILTER_CONNECTED,
                    
target_name,
                    
sizeof(target_name),
                    
tn_is_ml)) <= 0)
    {
        
ReplyToTargetError(clienttarget_count);
        return 
Plugin_Handled;
    }
    
    new 
itemID StringToInt(arg2);

    for (new 
0target_counti++)
    {
        
TF2_GivePlayerItem(clienttarget_list[i], itemID);        
    }
    
    return 
Plugin_Handled;
}

public 
Action:Command_Get(clientargs)
{
    if (
args != 1)
    {
        
ReplyToCommand(client"[SM] Usage: sm_get <itemindex>");
        return 
Plugin_Handled;
    }

    new 
String:arg1[32];
    
GetCmdArg(1arg1sizeof(arg1));
    new 
itemID StringToInt(arg1);

    
TF2_GivePlayerItem(clientclientitemID);        
    
    return 
Plugin_Handled;
}

public 
Action:TF2_GivePlayerItem(int iClientint iTargetint iItemID)
{
    if (!(
IsValidClient(iTarget) || IsPlayerAlive(iTarget)))
    {
        
PrintToChat(iClient"Target is Not Alive");
        return 
Plugin_Handled;
    }
    
    if(!
TF2Econ_IsValidItemDefinition(iItemID))
    {
        
PrintToChat(iClient"[SM] Invalid item definition index");
        return 
Plugin_Handled;
    }

    new 
iSlot TF2Econ_GetItemSlot(iItemIDTF2_GetPlayerClass(iTarget));
    if (
iSlot <0)
    {
        
PrintToChat(iClient"Item Index %i is invalid for target class"iItemID);
        return 
Plugin_Handled;
    }
    
    
//Information on Existing Item
    
new iOldSlotItem TF2_GetPlayerLoadoutSlot(iTargetTF2LoadoutSlot:iSlot); 
    
decl String:oldclassname[64];
    
GetEntityClassname(iOldSlotItemoldclassnamesizeof(oldclassname));
    new 
olditemDefinitionIndex GetEntProp(iOldSlotItemProp_Send"m_iItemDefinitionIndex");
    
decl String:olditemname[64];
    
TF2Econ_GetItemName(olditemDefinitionIndexolditemnamesizeof(olditemname));
    new 
iOldEnt iOldSlotItem;
    
PrintToChat(iClient"[Give Debug Old Item] %N Item Slot %d: ent %d, class \"%s\", index %d, itemname %s"iTargetiSlotiOldSlotItemoldclassnameolditemDefinitionIndexolditemname);

    
//Begin Creation of New Item
    
char strClassname[64];
    
TF2Econ_GetItemClassName(iItemIDstrClassnamesizeof(strClassname));
    
TF2Econ_TranslateWeaponEntForClass(strClassnamesizeof(strClassname), TF2_GetPlayerClass(iTarget));
    
int weaponprimary CreateEntityByName(strClassname);

    if (!
IsValidEntity(weaponprimary))
    {
        
PrintToChat(iClient,"Invalid Entity: Item Classname : %s"strClassname);    
        return 
Plugin_Handled;
    }

    
char entclass[64];
    
GetEntityNetClass(weaponprimaryentclasssizeof(entclass));
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iItemDefinitionIndex"), iItemID);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_bInitialized"), 1);
    
int iLevel GetRandomInt(1,99);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iEntityLevel"), iLevel);
    
int iQuality GetRandomInt(0,14);
    
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iEntityQuality"), iQuality);
    
TF2Attrib_SetByDefIndex(weaponprimary7250.2);

    switch (
iItemID)
    {
    case 
81083193310801102:
        {
            
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_iObjectType"), 3);
            
SetEntProp(weaponprimaryProp_Data"m_iSubType"3);
        }
    case 
998:
        {
            
SetEntData(weaponprimaryFindSendPropInfo(entclass"m_nChargeResistType"), GetRandomInt(0,2));
        }
    case 
1071:
        {
            
TF2Attrib_SetByName(weaponprimary"item style override"0.0);
            
TF2Attrib_SetByName(weaponprimary"loot rarity"1.0);        
            
TF2Attrib_SetByName(weaponprimary"turn to gold"1.0);
        }        
    }
    
    if (
TF2_IsWearable(weaponprimary))
    {
        
TF2_RemovePlayerWearable(iTargetiOldEnt);
        
DispatchSpawn(weaponprimary);
        
TF2_EquipPlayerWearable(iTargetweaponprimary);        
    }

    else
    {
        
TF2_RemoveWeapon(iTargetiOldEnt);
        
DispatchSpawn(weaponprimary);
        
EquipPlayerWeapon(iTargetweaponprimary);
    }
    
    
char strItemName[64];
    
TF2Econ_GetItemName(iItemIDstrItemNamesizeof(strItemName));
    
PrintToChat(iClient"Gave %s to %N"strItemNameiTarget);    
    
PrintToChat(iTarget"%N gave you a %s"iClientstrItemName);
    
    
#if DEBUG

    
PrintToChat(iClient"[Give Debug Old Item] %N Item Slot %d: ent %d, class \"%s\", index %d, itemname %s"iTargetiSlotiOldSlotItemoldclassnameolditemDefinitionIndexolditemname);

    
//New Item Info
    
char strQualityName[32];
    
TF2Econ_GetQualityName(iQualitystrQualityNamesizeof(strQualityName));

    
char strItemSlotName[32];
    
TF2Econ_TranslateLoadoutSlotIndexToName(iSlotstrItemSlotNamesizeof(strItemSlotName));

    
PrintToChat(iClient"[Give Debug]: Target Name : %N, Target Class : %i"iTargetTF2_GetPlayerClass(iTarget));
    
PrintToChat(iClient"[Give Debug]: Item Index : %i, Item Name : %s"iItemIDstrItemName);    
    
PrintToChat(iClient"[Give Debug]: Item Classname : %s"strClassname);
    
PrintToChat(iClient"[Give Debug]: iSlot : %i, iSlotName : %s"iSlotstrItemSlotName);
    
PrintToChat(iClient"[Give Debug]: iQuality : %i, iQualityName : %s"iQualitystrQualityName);
    
PrintToChat(iClient"[Give Debug]: iLevel : %i"iLevel);

    
#endif

    
return Plugin_Handled;
}

stock bool:IsValidClient(client)
{
    if (
client <= 0) return false;
    if (
client MaxClients) return false;
    return 
IsClientInGame(client);

PC Gamer is offline
Whai
Senior Member
Join Date: Jul 2018
Old 11-20-2019 , 11:40   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #9

The reason that I didn't use tf2 econ data is because of this:

Quote:
Originally Posted by https://github.com/nosoop/SM-TFEconData/wiki/Porting-TF2IDB-and-TF2II-plugins-to-TFEconData

TF2IDB_GetItemSlot() maps directly to TF2Econ_GetItemSlot(), with the following restrictions.
  • The player class must be specified, and -1 is the return value for invalid class / slot combinations.
Quote:
Originally Posted by PC Gamer View Post
I think maybe there is a problem with TF2_GetPlayerLoadoutSlot incorrectly because it always returns slot 8 for any wearable
So, did you also test on a weapon wearable ? like the index 131 (The Chargin' Targe) ?



If you want to remove a weapon wearable via the slot with tf2idb, use this :
PHP Code:
if(iSlot <= 5// we only want to remove weapon wearable not wearable
    
{
        
int iEntityiEntityIndexDefinition;
        while((
iEntity FindEntityByClassname(iEntity"tf_wearable*")) != INVALID_ENT_REFERENCE)
        {
            if(
iTarget != GetEntPropEnt(iEntityProp_Send"m_hOwnerEntity")) continue;
            
            
iEntityIndexDefinition GetEntProp(iEntityProp_Send"m_iItemDefinitionIndex");
            if(
view_as<int>(TF2IDB_GetItemSlot(iEntityIndexDefinition)) != iSlot) continue;
            
            
TF2_RemoveWearable(iTargetiEntity);
            break;
        }
    } 
__________________

Last edited by Whai; 11-20-2019 at 11:42.
Whai is offline
nosoop
Veteran Member
Join Date: Aug 2014
Old 11-20-2019 , 12:12   Re: [TF2] Client game crash when the client get a weapon
Reply With Quote #10

Quote:
Originally Posted by PC Gamer View Post
I think maybe there is a problem with TF2_GetPlayerLoadoutSlot incorrectly because it always returns slot 8 for any wearable. I tested this with the tf2wearables_test plugin and found similar result. In other words, when I have three wearable items equipped the 'checkmyitems' command will only show one wearable in slot 8.

The impact is that it when I try to remove an item it will usually remove the wrong item.

Any idea on what I can do to fix the problem?
Ah, my mistake; thought it'd show all the wearables there. I was also operating under the assumption that you were only dealing with wearable-based weapons and not actual cosmetics.

Besides the solution by iterating all wearables in the above post, you can also read from the client's m_hMyWearables property. However, it's pretty unsafe -- the offset isn't exposed by the game so you'll need to maintain that information yourself, and since SourceMod doesn't have any facilities to read entity handle / reference values from arbitrary memory locations (yet?), that's something you'd also have to do.

Otherwise, I'm not sure how you expect to identify which specific wearable you want to remove.

If you actually want to do that, here's a snippet for it.

Quote:
Originally Posted by Whai View Post
The reason that I didn't use tf2 econ data is because of this: [...]
That's what the schema supports. You can recreate the item slot functionality by parsing the item_slot schema value. That's pretty much what TF2II and TF2IDB would need to do.

If you've already instantiated a new weapon entity, you can also SDKCall its Weapon_GetSlot function to determine what weapon slot needs to be replaced.
__________________
I do TF2, TF2 servers, and TF2 plugins.
I don't do DMs over Discord -- PM me on the forums regarding inquiries.
AlliedModders Releases / Github / TF2 Server / Donate (BTC / BCH / coffee)
nosoop is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 11:11.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode