alliedmodders / sourcemod

SourceMod - Source Engine Scripting and Administration
http://www.sourcemod.net/
986 stars 423 forks source link

CS_GetWeaponPrice returning wrong value #670

Closed komashchenko closed 7 years ago

komashchenko commented 7 years ago

I'm getting the wrong price for weapons How to get the price for a revolver?

CT AK47 - 3100 M4A1 - 3100 T AK47 - 2700 M4A1 - 2700

#pragma newdecls required
#pragma semicolon 1
#include <cstrike>

public void OnPluginStart()
{
    RegConsoleCmd("sm_sr", Cmd_sr);
}

public Action Cmd_sr(int client, int args)
{
    PrintToChat(client, "AK47 - %d", CS_GetWeaponPrice(client, CSWeapon_AK47));
    PrintToChat(client, "M4A1 - %d", CS_GetWeaponPrice(client, CSWeapon_M4A1));
    return Plugin_Handled;
}

Build 6025

Drifter321 commented 7 years ago

Good catch, the issue here is that it is grabbing the CEconItemView of the loadoutslot but the function checks if slots are considered identical (ak -> m4, usp -> glock etc...) If they are identical it returns the item for the team the player is on, sadly if the player isnt on a team it simply returns an invalid CEConItemView so faking the team is also out. The only solution is to use the CEconItemDefinition to get CCSWeaponData... In linux there is a function, but in windows this is inlined...

I have solution in mind which is to replicate the function. Thankfully the function isnt long... But it requires getting a pointer and im not even sure what the pointer is to. It appears to be a pointer to what replaced the g_pCSWeaponDatabase pointer. Ill work on this tomorrow.

Kailo97 commented 7 years ago

"but in windows this is inlined" Yeah, inlined, but very well! And we still able to do call =) Let's look at GetCCSWeaponData function. We can do call only part of function, that will exacly like inlined function (__thiscall). Imgur I tested this:

#include <cstrike>
#include <sdktools>
#include <PTaH>

Handle g_config;
Handle g_call;
int g_priceoffset;

public void OnPluginStart()
{
    g_config = LoadGameConfigFile("sm-cstrike.games/game.csgo");
    if (g_config == null)
        SetFailState("g_config == null");
    Address pFunc = GameConfGetAddress(g_config, "Func_GetCCSWeaponData");
    if (pFunc == Address_Null)
        SetFailState("pFunc == Address_Null");
    int offset = GameConfGetOffset(g_config, "InlinedGetCSWeaponData");
    if (offset == -1)
        SetFailState("offset == -1");
    g_priceoffset = GameConfGetOffset(g_config, "WeaponPrice");
    if (g_priceoffset == -1)
        SetFailState("g_priceoffset == -1");
    StartPrepSDKCall(SDKCall_Raw);
    if (!PrepSDKCall_SetAddress(pFunc + view_as<Address>(offset)))
        SetFailState("SetAddress failed");
    PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
    // no params
    g_call = EndPrepSDKCall();
    if (g_call == null)
        SetFailState("g_call == null");

    Sub("weapon_ak47");
    Sub("weapon_m4a1");
    Sub("weapon_revolver");
}

void Sub(const char[] weapon)
{
    PrintToServer("%s price is %i", weapon, LoadFromAddress(view_as<Address>(SDKCall(g_call, PTaH_GetItemDefinitionByName(weapon)) + g_priceoffset), NumberType_Int32));
}

Gamedata override with "gamedata/custom/sm-cstrike.games/game.csgo.txt"

"Games"
{
    "csgo"
    {
        "Addresses"
        {
            "Func_GetCCSWeaponData"
            {
                "windows"
                {
                    "signature" "GetCCSWeaponData"
                }
            }
        }

        "Offsets"
        {
            "InlinedGetCSWeaponData"
            {
                "windows" "14"
            }
        }
    }
}

Result:

[SM] Parsed custom gamedata override file: custom/sm-cstrike.games/game.csgo.txt
weapon_ak47 price is 2700
weapon_m4a1 price is 3100
weapon_revolver price is 700
komashchenko commented 7 years ago

Maybe it's worth to give up https://sm.alliedmods.net/new-api/cstrike/CSWeaponID CSGO has its DefinitionIndex which is all weapon * and item * ?

Drifter321 commented 7 years ago

We cant easily give up on CSWeaponID due to old plugins relying on the current logic. We are already thinking of a way to introduce the indexes without breaking old plugins completely at least right away. That is why the fix was refereed to as a temporary fix.

I wanted to avoid calling the inlined code directly but I couldn't replicate the code so I went along with using/abusing the inlined code. My original concern with this was the possible ease to break, but also the fact that its pretty abusive since you assume that the itemdef will be stored in the ecx register... if that changes it becomes harder. Although this might be unlikely to change.

komashchenko commented 7 years ago

https://github.com/alliedmodders/sourcemod/blob/22033c21f293ca6d9cbb333b6e9db1cc84cf469e/extensions/cstrike/natives.cpp#L484-L489 I think it can be removed because it no longer requires