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

Commit

Permalink
Added m_nSequence hook to fix some knife animations.
Browse files Browse the repository at this point in the history
  • Loading branch information
aixxe committed Jan 2, 2016
1 parent 2c23331 commit 97c58c6
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 53 deletions.
62 changes: 22 additions & 40 deletions Chameleon/Chameleon.cpp
Expand Up @@ -14,42 +14,13 @@
// Include the user defined skins.
#include "Skins.h"

// Include the NetVar proxy functions.
#include "Proxies.h"

// 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()) {
// 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.
fnOriginalProxyFn(pData, pStruct, pOut);
}

// Function to apply skin data to weapons.
inline bool ApplyCustomSkin(CBaseAttributableItem* pWeapon) {
// Get the weapons item definition index.
Expand Down Expand Up @@ -178,16 +149,28 @@ void Initialise() {
for (int nIndex = 0; nIndex < pClassTable->m_nProps; nIndex++) {
RecvProp* pProp = &pClassTable->m_pProps[nIndex];

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

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

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

continue;
}

break;
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;
Expand All @@ -196,9 +179,8 @@ void Initialise() {
}

bool __stdcall DllMain(HINSTANCE hDLLInstance, DWORD dwReason, LPVOID lpReserved) {
if (dwReason == DLL_PROCESS_ATTACH) {
if (dwReason == DLL_PROCESS_ATTACH)
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Initialise, 0, 0, 0);
}

return true;
}
1 change: 1 addition & 0 deletions Chameleon/Chameleon.vcxproj
Expand Up @@ -82,6 +82,7 @@
<ClInclude Include="ClientClass.h" />
<ClInclude Include="DataTable.h" />
<ClInclude Include="Defines.h" />
<ClInclude Include="Proxies.h" />
<ClInclude Include="IBaseClientDLL.h" />
<ClInclude Include="IClientEntity.h" />
<ClInclude Include="IClientEntityList.h" />
Expand Down
3 changes: 3 additions & 0 deletions Chameleon/Chameleon.vcxproj.filters
Expand Up @@ -54,6 +54,9 @@
<ClInclude Include="IVModelInfoClient.h">
<Filter>Header Files\Source SDK\Classes</Filter>
</ClInclude>
<ClInclude Include="Proxies.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Chameleon.cpp">
Expand Down
29 changes: 29 additions & 0 deletions Chameleon/Defines.h
@@ -1,7 +1,36 @@
#pragma once

#define SEQUENCE_DEFAULT_DRAW 0
#define SEQUENCE_DEFAULT_IDLE1 1
#define SEQUENCE_DEFAULT_IDLE2 2
#define SEQUENCE_DEFAULT_LIGHT_MISS1 3
#define SEQUENCE_DEFAULT_LIGHT_MISS2 4
#define SEQUENCE_DEFAULT_HEAVY_MISS1 9
#define SEQUENCE_DEFAULT_HEAVY_HIT1 10
#define SEQUENCE_DEFAULT_HEAVY_BACKSTAB 11
#define SEQUENCE_DEFAULT_LOOKAT01 12

#define SEQUENCE_BUTTERFLY_DRAW 0
#define SEQUENCE_BUTTERFLY_DRAW2 1
#define SEQUENCE_BUTTERFLY_LOOKAT01 13
#define SEQUENCE_BUTTERFLY_LOOKAT03 15

#define SEQUENCE_FALCHION_IDLE1 1
#define SEQUENCE_FALCHION_HEAVY_MISS1 8
#define SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP 9
#define SEQUENCE_FALCHION_LOOKAT01 12
#define SEQUENCE_FALCHION_LOOKAT02 13

#define SEQUENCE_DAGGERS_IDLE1 1
#define SEQUENCE_DAGGERS_LIGHT_MISS1 2
#define SEQUENCE_DAGGERS_LIGHT_MISS5 6
#define SEQUENCE_DAGGERS_HEAVY_MISS2 11
#define SEQUENCE_DAGGERS_HEAVY_MISS1 12

#define LIFE_ALIVE 0

#define RandomInt(nMin, nMax) (rand() % (nMax - nMin + 1) + nMin);

typedef struct player_info_s {
private:
DWORD __pad0[2];
Expand Down
18 changes: 12 additions & 6 deletions Chameleon/IClientEntity.h
Expand Up @@ -3,6 +3,9 @@
#define m_lifeState 0x25B
#define m_hMyWeapons 0x49F8

#define m_nModelIndex 0x254
#define m_hOwner 0x45CC

#define m_AttributeManager 0x4980
#define m_Item 0x40
#define m_iItemDefinitionIndex 0x1D0
Expand All @@ -17,8 +20,6 @@
#define m_flFallbackWear 0x4D78
#define m_nFallbackStatTrak 0x4D7C

#define m_hOwner 0x45CC

class IClientEntity {
public:
inline BYTE GetLifeState() {
Expand All @@ -32,15 +33,20 @@ class IClientEntity {
}
};

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

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

class CBaseAttributableItem: IClientEntity {
class CBaseAttributableItem: public IClientEntity {
public:
inline int* GetItemDefinitionIndex() {
// DT_BaseAttributableItem -> m_AttributeManager -> m_Item -> m_iItemDefinitionIndex
Expand Down
1 change: 0 additions & 1 deletion Chameleon/IClientEntityList.h
Expand Up @@ -8,6 +8,5 @@ class IClientEntityList {

inline IClientEntity* GetClientEntityFromHandle(DWORD Handle) {
return CallVirtualFunction<IClientEntity*(__thiscall *)(void *, int)>(this, 4)(this, Handle);
//return this->GetClientEntity(Handle & 0xFFFF);
}
};
8 changes: 8 additions & 0 deletions Chameleon/IVModelInfoClient.h
Expand Up @@ -2,7 +2,15 @@

class IVModelInfoClient {
public:
inline void* GetModel(int Index) {
return CallVirtualFunction<void*(__thiscall *)(void*, int)>(this, 1)(this, Index);
}

inline int GetModelIndex(const char* Filename) {
return CallVirtualFunction<int(__thiscall *)(void*, const char*)>(this, 2)(this, Filename);
}

inline const char* GetModelName(const void* Model) {
return CallVirtualFunction<const char*(__thiscall *)(void*, const void*)>(this, 3)(this, Model);
}
};
108 changes: 108 additions & 0 deletions Chameleon/Proxies.h
@@ -0,0 +1,108 @@
#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;

// 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);

// 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++;
}
} 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;
}

// Call original function with the modified data.
fnSequenceProxyFn(pData, pStruct, pOut);
}
18 changes: 12 additions & 6 deletions Chameleon/SDK.h
Expand Up @@ -3,16 +3,22 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

class IBaseClientDLL;
class IVEngineClient;
class IClientEntityList;
class IVModelInfoClient;
class IClientEntity;

IBaseClientDLL* g_BaseClient = nullptr;
IVEngineClient* g_EngineClient = nullptr;
IClientEntityList* g_EntityList = nullptr;
IVModelInfoClient* g_ModelInfo = nullptr;

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

IBaseClientDLL* g_BaseClient = nullptr;
IVEngineClient* g_EngineClient = nullptr;
IClientEntityList* g_EntityList = nullptr;
IVModelInfoClient* g_ModelInfo = nullptr;
#include "IClientEntity.h"

0 comments on commit 97c58c6

Please sign in to comment.