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

Commit

Permalink
Replace m_nModelIndex hook with call to CBaseViewModel::SetWeaponModel.
Browse files Browse the repository at this point in the history
  • Loading branch information
aixxe committed Jan 2, 2016
1 parent 97c58c6 commit 756c6fd
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 125 deletions.
69 changes: 45 additions & 24 deletions Chameleon/Chameleon.cpp
Expand Up @@ -22,10 +22,7 @@ typedef void(__thiscall *FrameStageNotify)(void*, ClientFrameStage_t);
FrameStageNotify fnOriginalFunction = NULL;

// Function to apply skin data to weapons.
inline bool ApplyCustomSkin(CBaseAttributableItem* pWeapon) {
// Get the weapons item definition index.
int nWeaponIndex = *pWeapon->GetItemDefinitionIndex();

inline bool ApplyCustomSkin(CBaseAttributableItem* pWeapon, int nWeaponIndex) {
// Check if this weapon has a valid override defined.
if (g_SkinChangerCfg.find(nWeaponIndex) == g_SkinChangerCfg.end())
return false;
Expand All @@ -51,11 +48,42 @@ inline bool ApplyCustomSkin(CBaseAttributableItem* pWeapon) {
return true;
}

// Function to apply custom view models to weapons.
inline bool ApplyCustomModel(CBasePlayer* pLocal, CBaseAttributableItem* pWeapon, int nWeaponIndex) {
// Get the view model of this weapon.
CBaseViewModel* pViewModel = pLocal->GetViewModel();

if (!pViewModel)
return false;

// Get the weapon belonging to this view model.
DWORD hViewModelWeapon = pViewModel->GetWeapon();
CBaseAttributableItem* pViewModelWeapon = (CBaseAttributableItem*)g_EntityList->GetClientEntityFromHandle(hViewModelWeapon);

if (pViewModelWeapon != pWeapon)
return false;

// Check if an override exists for this view model.
int nViewModelIndex = pViewModel->GetModelIndex();

if (g_ViewModelCfg.find(nViewModelIndex) == g_ViewModelCfg.end())
return false;

// Set the replacement model.
pViewModel->SetWeaponModel(g_ViewModelCfg[nViewModelIndex], pWeapon);

return true;
}

void __fastcall FrameStageNotifyThink(void* ecx, void* edx, ClientFrameStage_t Stage) {
while (Stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START) {
// Populate g_ViewModelCfg while in-game so IVModelInfoClient::GetModelIndex returns correctly.
if (g_ViewModelCfg.size() == 0)
SetModelConfig();

// Get our player entity.
int nLocalPlayerID = g_EngineClient->GetLocalPlayer();
IClientEntity* pLocal = g_EntityList->GetClientEntity(nLocalPlayerID);
CBasePlayer* pLocal = (CBasePlayer*)g_EntityList->GetClientEntity(nLocalPlayerID);

// Don't change anything if we're not alive.
if (!pLocal || pLocal->GetLifeState() != LIFE_ALIVE)
Expand All @@ -79,14 +107,19 @@ void __fastcall FrameStageNotifyThink(void* ecx, void* edx, ClientFrameStage_t S
if (!pWeapon)
continue;

// Get the weapons item definition index.
int nWeaponIndex = *pWeapon->GetItemDefinitionIndex();

ApplyCustomModel(pLocal, pWeapon, nWeaponIndex);

// Compare original owner XUIDs.
if (LocalPlayerInfo.m_nXuidLow != *pWeapon->GetOriginalOwnerXuidLow())
continue;

if (LocalPlayerInfo.m_nXuidHigh != *pWeapon->GetOriginalOwnerXuidHigh())
continue;

ApplyCustomSkin(pWeapon);
ApplyCustomSkin(pWeapon, nWeaponIndex);

// Fix up the account ID so StatTrak will display correctly.
*pWeapon->GetAccountID() = LocalPlayerInfo.m_nXuidLow;
Expand Down Expand Up @@ -149,28 +182,16 @@ void Initialise() {
for (int nIndex = 0; nIndex < pClassTable->m_nProps; nIndex++) {
RecvProp* pProp = &pClassTable->m_pProps[nIndex];

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

if (!strcmp(pProp->m_pVarName, "m_nModelIndex")) {
// Store the original proxy function.
fnModelIndexProxyFn = pProp->m_ProxyFn;
// Store the original proxy function.
fnSequenceProxyFn = pProp->m_ProxyFn;

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

continue;
}

if (!strcmp(pProp->m_pVarName, "m_nSequence")) {
// Store the original proxy function.
fnSequenceProxyFn = pProp->m_ProxyFn;

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

continue;
}
break;
}

break;
Expand Down
49 changes: 37 additions & 12 deletions Chameleon/IClientEntity.h
@@ -1,10 +1,14 @@
#pragma once

#define m_lifeState 0x25B
#define m_hMyWeapons 0x49F8
#define m_nIndex 0x64

#define m_nModelIndex 0x254
#define m_hOwner 0x45CC
#define m_hWeapon 0x45C8

#define m_lifeState 0x25B
#define m_hMyWeapons 0x49F8
#define m_hViewModel 0x4EFC

#define m_AttributeManager 0x4980
#define m_Item 0x40
Expand All @@ -22,28 +26,49 @@

class IClientEntity {
public:
inline BYTE GetLifeState() {
// DT_BasePlayer -> m_lifeState
return *(BYTE*)((DWORD)this + m_lifeState);
}

inline UINT* GetWeapons() {
// DT_BasePlayer -> m_hMyWeapons
return (UINT*)((DWORD)this + m_hMyWeapons);
inline int GetIndex() {
return *(int*)((DWORD)this + m_nIndex);
}
};

class CBaseViewModel: public IClientEntity {
public:
inline int* GetModelIndex() {
inline int GetModelIndex() {
// DT_BaseViewModel -> m_nModelIndex
return (int*)((DWORD)this + m_nModelIndex);
return *(int*)((DWORD)this + m_nModelIndex);
}

inline DWORD GetOwner() {
// DT_BaseViewModel -> m_hOwner
return *(PDWORD)((DWORD)this + m_hOwner);
}

inline DWORD GetWeapon() {
// DT_BaseViewModel -> m_hWeapon
return *(PDWORD)((DWORD)this + m_hWeapon);
}

inline void SetWeaponModel(const char* Filename, IClientEntity* Weapon) {
return CallVirtualFunction<void(__thiscall*)(void*, const char*, IClientEntity*)>(this, 241)(this, Filename, Weapon);
}
};

class CBasePlayer: public IClientEntity {
public:
inline BYTE GetLifeState() {
// DT_BasePlayer -> m_lifeState
return *(BYTE*)((DWORD)this + m_lifeState);
}

inline UINT* GetWeapons() {
// DT_BasePlayer -> m_hMyWeapons
return (UINT*)((DWORD)this + m_hMyWeapons);
}

inline CBaseViewModel* GetViewModel() {
// DT_BasePlayer -> m_hViewModel
return (CBaseViewModel*)g_EntityList->GetClientEntityFromHandle(*(PDWORD)(this + m_hViewModel));
}
};

class CBaseAttributableItem: public IClientEntity {
Expand Down
144 changes: 58 additions & 86 deletions Chameleon/Proxies.h
@@ -1,106 +1,78 @@
#pragma once

// Store the original proxy functions.
RecvVarProxyFn fnModelIndexProxyFn = NULL;
RecvVarProxyFn fnSequenceProxyFn = 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()) {
// Confirm that we are replacing our view model and not someone elses.
CBaseViewModel* pViewModel = (CBaseViewModel*)pStruct;

if (pViewModel) {
// Compare the owner entity of this view model to the local player entity.
IClientEntity* pLocal = g_EntityList->GetClientEntity(g_EngineClient->GetLocalPlayer());

if (pLocal == g_EntityList->GetClientEntityFromHandle(pViewModel->GetOwner())) {
// 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.
fnModelIndexProxyFn(pData, pStruct, pOut);
}

// Function to fix sequences for certain models.
void SetViewModelSequence(const CRecvProxyData *pDataConst, void *pStruct, void *pOut) {
// Make the incoming data editable.
CRecvProxyData* pData = const_cast<CRecvProxyData*>(pDataConst);

// Confirm that we are replacing our view model and not someone elses.
CBaseViewModel* pViewModel = (CBaseViewModel*)pStruct;

if (pViewModel) {
IClientEntity* pOwner = g_EntityList->GetClientEntityFromHandle(pViewModel->GetOwner());

// Compare the owner entity of this view model to the local player entity.
IClientEntity* pLocal = g_EntityList->GetClientEntity(g_EngineClient->GetLocalPlayer());

if (pLocal == g_EntityList->GetClientEntityFromHandle(pViewModel->GetOwner())) {
// Get the filename of the current view model.
void* pModel = g_ModelInfo->GetModel(*pViewModel->GetModelIndex());
const char* szModel = g_ModelInfo->GetModelName(pModel);
// Compare the owner entity of this view model to the local player entity.
if (pOwner && pOwner->GetIndex() == g_EngineClient->GetLocalPlayer()) {
// Get the filename of the current view model.
void* pModel = g_ModelInfo->GetModel(pViewModel->GetModelIndex());
const char* szModel = g_ModelInfo->GetModelName(pModel);

// Store the current sequence.
int m_nSequence = pData->m_Value.m_Int;
// Store the current sequence.
int m_nSequence = pData->m_Value.m_Int;

if (!strcmp(szModel, "models/weapons/v_knife_butterfly.mdl")) {
// Fix animations for the Butterfly Knife.
switch (m_nSequence) {
case SEQUENCE_DEFAULT_DRAW:
m_nSequence = RandomInt(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2); break;
case SEQUENCE_DEFAULT_LOOKAT01:
m_nSequence = RandomInt(SEQUENCE_BUTTERFLY_LOOKAT01, SEQUENCE_BUTTERFLY_LOOKAT03); break;
default:
m_nSequence++;
if (!strcmp(szModel, "models/weapons/v_knife_butterfly.mdl")) {
// Fix animations for the Butterfly Knife.
switch (m_nSequence) {
case SEQUENCE_DEFAULT_DRAW:
m_nSequence = RandomInt(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2); break;
case SEQUENCE_DEFAULT_LOOKAT01:
m_nSequence = RandomInt(SEQUENCE_BUTTERFLY_LOOKAT01, SEQUENCE_BUTTERFLY_LOOKAT03); break;
default:
m_nSequence++;
}
} else if (!strcmp(szModel, "models/weapons/v_knife_falchion_advanced.mdl")) {
// Fix animations for the Falchion Knife.
switch (m_nSequence) {
case SEQUENCE_DEFAULT_IDLE2:
m_nSequence = SEQUENCE_FALCHION_IDLE1; break;
case SEQUENCE_DEFAULT_HEAVY_MISS1:
m_nSequence = RandomInt(SEQUENCE_FALCHION_HEAVY_MISS1, SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP); break;
case SEQUENCE_DEFAULT_LOOKAT01:
m_nSequence = RandomInt(SEQUENCE_FALCHION_LOOKAT01, SEQUENCE_FALCHION_LOOKAT02); break;
case SEQUENCE_DEFAULT_DRAW:
case SEQUENCE_DEFAULT_IDLE1:
break;
default:
m_nSequence--;
}
} else if (!strcmp(szModel, "models/weapons/v_knife_push.mdl")) {
// Fix animations for the Shadow Daggers.
switch (m_nSequence) {
case SEQUENCE_DEFAULT_IDLE2:
m_nSequence = SEQUENCE_DAGGERS_IDLE1; break;
case SEQUENCE_DEFAULT_LIGHT_MISS1:
case SEQUENCE_DEFAULT_LIGHT_MISS2:
m_nSequence = RandomInt(SEQUENCE_DAGGERS_LIGHT_MISS1, SEQUENCE_DAGGERS_LIGHT_MISS5); break;
case SEQUENCE_DEFAULT_HEAVY_MISS1:
m_nSequence = RandomInt(SEQUENCE_DAGGERS_HEAVY_MISS2, SEQUENCE_DAGGERS_HEAVY_MISS1); break;
case SEQUENCE_DEFAULT_HEAVY_HIT1:
case SEQUENCE_DEFAULT_HEAVY_BACKSTAB:
case SEQUENCE_DEFAULT_LOOKAT01:
m_nSequence += 3; break;
case SEQUENCE_DEFAULT_DRAW:
case SEQUENCE_DEFAULT_IDLE1:
break;
default:
m_nSequence += 2;
}
}
} else if (!strcmp(szModel, "models/weapons/v_knife_falchion_advanced.mdl")) {
// Fix animations for the Falchion Knife.
switch (m_nSequence) {
case SEQUENCE_DEFAULT_IDLE2:
m_nSequence = SEQUENCE_FALCHION_IDLE1; break;
case SEQUENCE_DEFAULT_HEAVY_MISS1:
m_nSequence = RandomInt(SEQUENCE_FALCHION_HEAVY_MISS1, SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP); break;
case SEQUENCE_DEFAULT_LOOKAT01:
m_nSequence = RandomInt(SEQUENCE_FALCHION_LOOKAT01, SEQUENCE_FALCHION_LOOKAT02); break;
case SEQUENCE_DEFAULT_DRAW:
case SEQUENCE_DEFAULT_IDLE1:
break;
default:
m_nSequence--;
}
} else if (!strcmp(szModel, "models/weapons/v_knife_push.mdl")) {
// Fix animations for the Shadow Daggers.
switch (m_nSequence) {
case SEQUENCE_DEFAULT_IDLE2:
m_nSequence = SEQUENCE_DAGGERS_IDLE1; break;
case SEQUENCE_DEFAULT_LIGHT_MISS1:
case SEQUENCE_DEFAULT_LIGHT_MISS2:
m_nSequence = RandomInt(SEQUENCE_DAGGERS_LIGHT_MISS1, SEQUENCE_DAGGERS_LIGHT_MISS5); break;
case SEQUENCE_DEFAULT_HEAVY_MISS1:
m_nSequence = RandomInt(SEQUENCE_DAGGERS_HEAVY_MISS2, SEQUENCE_DAGGERS_HEAVY_MISS1); break;
case SEQUENCE_DEFAULT_HEAVY_HIT1:
case SEQUENCE_DEFAULT_HEAVY_BACKSTAB:
case SEQUENCE_DEFAULT_LOOKAT01:
m_nSequence += 3; break;
case SEQUENCE_DEFAULT_DRAW:
case SEQUENCE_DEFAULT_IDLE1:
break;
default:
m_nSequence += 2;
}
}

// Set the fixed sequence.
pData->m_Value.m_Int = m_nSequence;
// Set the fixed sequence.
pData->m_Value.m_Int = m_nSequence;
}
}

// Call original function with the modified data.
Expand Down
6 changes: 3 additions & 3 deletions Chameleon/Skins.h
Expand Up @@ -13,7 +13,7 @@ struct EconomyItemCfg {
};

std::unordered_map<int, EconomyItemCfg> g_SkinChangerCfg;
std::unordered_map<int, int> g_ViewModelCfg;
std::unordered_map<int, const char*> g_ViewModelCfg;

inline void SetSkinConfig() {
// StatTrak™ AWP | Dragon Lore
Expand Down Expand Up @@ -56,6 +56,6 @@ inline void SetModelConfig() {
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");
g_ViewModelCfg[nOriginalKnifeCT] = "models/weapons/v_knife_karam.mdl";
g_ViewModelCfg[nOriginalKnifeT] = "models/weapons/v_knife_m9_bay.mdl";
}

0 comments on commit 756c6fd

Please sign in to comment.