Skip to content
This repository has been archived by the owner on Jul 8, 2022. It is now read-only.

Commit

Permalink
Add basic knife changer through NetVar proxy function.
Browse files Browse the repository at this point in the history
  • Loading branch information
aixxe committed Dec 29, 2015
1 parent c6a1072 commit 784387c
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 11 deletions.
65 changes: 55 additions & 10 deletions Chameleon/Chameleon.cpp
Expand Up @@ -4,14 +4,32 @@
// Include the user defined skins.
#include "Skins.h"

// Define global pointers to game classes.
IVEngineClient* g_EngineClient = nullptr;
IClientEntityList* g_EntityList = nullptr;

// Define the calling convention for the FrameStageNotify function.
typedef void(__thiscall *FrameStageNotify)(void*, ClientFrameStage_t);
FrameStageNotify fnOriginalFunction = NULL;

// Store the original proxy function for the 'm_nModelIndex' property.
RecvVarProxyFn fnOriginalProxyFn = NULL;

// Function to change viewmodels.
void SetViewModelIndex(const CRecvProxyData *pDataConst, void *pStruct, void *pOut) {
// Ensure the model replacements are available. (called here so GetModelIndex returns valid IDs)
if (g_ViewModelCfg.size() == 0)
SetModelConfig();

// Make the incoming data editable.
CRecvProxyData* pData = const_cast<CRecvProxyData*>(pDataConst);

// Check for a model replacement in the global table.
if (g_ViewModelCfg.find(pData->m_Value.m_Int) != g_ViewModelCfg.end()) {
// Replace the view model with the user defined value.
pData->m_Value.m_Int = g_ViewModelCfg[pData->m_Value.m_Int];
}

// Call original function with the modified data.
fnOriginalProxyFn(pData, pStruct, pOut);
}

// Function to apply skin data to weapons.
inline bool ApplyCustomSkin(CBaseAttributableItem* pWeapon) {
// Get the weapons item definition index.
Expand All @@ -28,6 +46,9 @@ inline bool ApplyCustomSkin(CBaseAttributableItem* pWeapon) {
*pWeapon->GetFallbackStatTrak() = g_SkinChangerCfg[nWeaponIndex].nFallbackStatTrak;
*pWeapon->GetFallbackWear() = g_SkinChangerCfg[nWeaponIndex].flFallbackWear;

if (g_SkinChangerCfg[nWeaponIndex].iItemDefinitionIndex)
*pWeapon->GetItemDefinitionIndex() = g_SkinChangerCfg[nWeaponIndex].iItemDefinitionIndex;

// If a name is defined, write it now.
if (g_SkinChangerCfg[nWeaponIndex].szCustomName) {
sprintf_s(pWeapon->GetCustomName(), 32, "%s", g_SkinChangerCfg[nWeaponIndex].szCustomName);
Expand Down Expand Up @@ -89,15 +110,14 @@ void Initialise() {
CreateInterfaceFn fnClientFactory = (CreateInterfaceFn)GetProcAddress(GetModuleHandleA("client.dll"), "CreateInterface");
CreateInterfaceFn fnEngineFactory = (CreateInterfaceFn)GetProcAddress(GetModuleHandleA("engine.dll"), "CreateInterface");

// Call "CreateInterface" to get the IBaseClientDLL, IClientEntityList and IVEngineClient classes.
// Call "CreateInterface" to get the required class pointers.
g_BaseClient = (IBaseClientDLL*)fnClientFactory("VClient017", NULL);
g_EntityList = (IClientEntityList*)fnClientFactory("VClientEntityList003", NULL);
g_EngineClient = (IVEngineClient*)fnEngineFactory("VEngineClient013", NULL);

// We don't implement IBaseClientDLL so we won't cast it.
void* pClientDLL = fnClientFactory("VClient017", NULL);

g_ModelInfo = (IVModelInfoClient*)fnEngineFactory("VModelInfoClient004", NULL);

// Get the virtual method table for IBaseClientDLL.
PDWORD* pClientDLLVMT = (PDWORD*)pClientDLL;
PDWORD* pClientDLLVMT = (PDWORD*)g_BaseClient;

// Save the untouched table so we know where the original functions are.
PDWORD pOriginalClientDLLVMT = *pClientDLLVMT;
Expand Down Expand Up @@ -125,6 +145,31 @@ void Initialise() {

// Import skins to use.
SetSkinConfig();

// Search for the 'CBaseViewModel' class.
for (ClientClass* pClass = g_BaseClient->GetAllClasses(); pClass; pClass = pClass->m_pNext) {
if (!strcmp(pClass->m_pNetworkName, "CBaseViewModel")) {
// Search for the 'm_nModelIndex' property.
RecvTable* pClassTable = pClass->m_pRecvTable;

for (int nIndex = 0; nIndex < pClassTable->m_nProps; nIndex++) {
RecvProp* pProp = &pClassTable->m_pProps[nIndex];

if (!pProp || strcmp(pProp->m_pVarName, "m_nModelIndex"))
continue;

// Store the original proxy function.
fnOriginalProxyFn = pProp->m_ProxyFn;

// Replace the proxy function with our model changer.
pProp->m_ProxyFn = (RecvVarProxyFn)SetViewModelIndex;

break;
}

break;
}
}
}

bool __stdcall DllMain(HINSTANCE hDLLInstance, DWORD dwReason, LPVOID lpReserved) {
Expand Down
4 changes: 4 additions & 0 deletions Chameleon/Chameleon.vcxproj
Expand Up @@ -79,10 +79,14 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ClientClass.h" />
<ClInclude Include="DataTable.h" />
<ClInclude Include="Defines.h" />
<ClInclude Include="IBaseClientDLL.h" />
<ClInclude Include="IClientEntity.h" />
<ClInclude Include="IClientEntityList.h" />
<ClInclude Include="IVEngineClient.h" />
<ClInclude Include="IVModelInfoClient.h" />
<ClInclude Include="SDK.h" />
<ClInclude Include="Skins.h" />
</ItemGroup>
Expand Down
12 changes: 12 additions & 0 deletions Chameleon/Chameleon.vcxproj.filters
Expand Up @@ -42,6 +42,18 @@
<ClInclude Include="SDK.h">
<Filter>Header Files\Source SDK</Filter>
</ClInclude>
<ClInclude Include="DataTable.h">
<Filter>Header Files\Source SDK\Classes</Filter>
</ClInclude>
<ClInclude Include="ClientClass.h">
<Filter>Header Files\Source SDK\Classes</Filter>
</ClInclude>
<ClInclude Include="IBaseClientDLL.h">
<Filter>Header Files\Source SDK\Classes</Filter>
</ClInclude>
<ClInclude Include="IVModelInfoClient.h">
<Filter>Header Files\Source SDK\Classes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Chameleon.cpp">
Expand Down
11 changes: 11 additions & 0 deletions Chameleon/ClientClass.h
@@ -0,0 +1,11 @@
#pragma once

class ClientClass {
private:
char __pad[0x8];
public:
char* m_pNetworkName;
RecvTable* m_pRecvTable;
ClientClass* m_pNext;
int m_ClassID;
};
53 changes: 53 additions & 0 deletions Chameleon/DataTable.h
@@ -0,0 +1,53 @@
#pragma once

struct RecvProp;

struct DVariant {
union {
float m_Float;
long m_Int;
char* m_pString;
void* m_pData;
float m_Vector[3];
__int64 m_Int64;
};

int m_Type;
};

struct CRecvProxyData {
const RecvProp* m_pRecvProp;
DVariant m_Value;
int m_iElement;
int m_ObjectID;
};

struct RecvTable {
public:
RecvProp* m_pProps;
int m_nProps;
void* m_pDecoder;
char* m_pNetTableName;
private:
char pad00[2];
};

typedef void(__cdecl *RecvVarProxyFn)(const CRecvProxyData*, void*, void*);

struct RecvProp {
char* m_pVarName;
int m_RecvType;
int m_Flags;
int m_StringBufferSize;
bool m_bInsideArray;
const void* m_pExtraData;
RecvProp* m_pArrayProp;
void* m_ArrayLengthProxy;
RecvVarProxyFn m_ProxyFn;
void* m_DataTableProxyFn;
RecvTable* m_pDataTable;
int m_Offset;
int m_ElementStride;
int m_nElements;
const char* m_pParentArrayPropName;
};
8 changes: 8 additions & 0 deletions Chameleon/IBaseClientDLL.h
@@ -0,0 +1,8 @@
#pragma once

class IBaseClientDLL {
public:
inline ClientClass* GetAllClasses() {
return CallVirtualFunction<ClientClass*(__thiscall *)(void*)>(this, 8)(this);
}
};
8 changes: 8 additions & 0 deletions Chameleon/IVModelInfoClient.h
@@ -0,0 +1,8 @@
#pragma once

class IVModelInfoClient {
public:
inline int GetModelIndex(const char* Filename) {
return CallVirtualFunction<int(__thiscall *)(void*, const char*)>(this, 2)(this, Filename);
}
};
11 changes: 10 additions & 1 deletion Chameleon/SDK.h
Expand Up @@ -4,6 +4,15 @@
#include <windows.h>

#include "Defines.h"
#include "DataTable.h"
#include "ClientClass.h"
#include "IClientEntity.h"
#include "IBaseClientDLL.h"
#include "IVEngineClient.h"
#include "IClientEntityList.h"
#include "IVModelInfoClient.h"
#include "IClientEntityList.h"

IBaseClientDLL* g_BaseClient = nullptr;
IVEngineClient* g_EngineClient = nullptr;
IClientEntityList* g_EntityList = nullptr;
IVModelInfoClient* g_ModelInfo = nullptr;
22 changes: 22 additions & 0 deletions Chameleon/Skins.h
Expand Up @@ -3,6 +3,7 @@
#include <unordered_map>

struct EconomyItemCfg {
int iItemDefinitionIndex = 0;
int nFallbackPaintKit = 0;
int nFallbackSeed = 0;
int nFallbackStatTrak = -1;
Expand All @@ -12,6 +13,7 @@ struct EconomyItemCfg {
};

std::unordered_map<int, EconomyItemCfg> g_SkinChangerCfg;
std::unordered_map<int, int> g_ViewModelCfg;

inline void SetSkinConfig() {
// StatTrak™ AWP | Dragon Lore
Expand All @@ -36,4 +38,24 @@ inline void SetSkinConfig() {

// USP-S | Stainless
g_SkinChangerCfg[WEAPON_USP_SILENCER].nFallbackPaintKit = 277;

// Karambit | Fade (CT)
g_SkinChangerCfg[WEAPON_KNIFE].iItemDefinitionIndex = WEAPON_KNIFE_KARAMBIT;
g_SkinChangerCfg[WEAPON_KNIFE].nFallbackPaintKit = 38;
g_SkinChangerCfg[WEAPON_KNIFE].iEntityQuality = 3;

// M9 Bayonet | Crimson Web (T)
g_SkinChangerCfg[WEAPON_KNIFE_T].iItemDefinitionIndex = WEAPON_KNIFE_M9_BAYONET;
g_SkinChangerCfg[WEAPON_KNIFE_T].nFallbackPaintKit = 12;
g_SkinChangerCfg[WEAPON_KNIFE_T].iEntityQuality = 3;
}

inline void SetModelConfig() {
// Get the indexes of the models we want to replace.
int nOriginalKnifeCT = g_ModelInfo->GetModelIndex("models/weapons/v_knife_default_ct.mdl");
int nOriginalKnifeT = g_ModelInfo->GetModelIndex("models/weapons/v_knife_default_t.mdl");

// Configure model replacements.
g_ViewModelCfg[nOriginalKnifeCT] = g_ModelInfo->GetModelIndex("models/weapons/v_knife_karam.mdl");
g_ViewModelCfg[nOriginalKnifeT] = g_ModelInfo->GetModelIndex("models/weapons/v_knife_m9_bay.mdl");
}

0 comments on commit 784387c

Please sign in to comment.