Skip to content

Commit

Permalink
Merge branch 'release/0.23.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
thesupremecommander committed Dec 22, 2014
2 parents 09000c8 + 700dd20 commit 753b52c
Show file tree
Hide file tree
Showing 61 changed files with 2,661 additions and 1,138 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ a Team Fortress 2 client plugin that augments game spectating
Changelog
---------

**0.23.0**
* general
* major modularization - modules check dependencies and fail separately
* revamp support structures
* fix incompatibilities between modules
* killstreaks
* fixed changes from recent updates
* loadout icons
* fixed recent issues

**0.22.3**
* general
* fix issues with multiple detours causing crashes
Expand Down
126 changes: 126 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* common.h
* StatusSpec project
*
* Copyright (c) 2014 thesupremecommander
* BSD 2-Clause License
* http://opensource.org/licenses/BSD-2-Clause
*
*/

#pragma once

#include "stdafx.h"

#include <cstdint>
#include <sstream>
#include <string>
#include <vector>

#include "Color.h"
#include "convar.h"
#include "steam/steamclientpublic.h"

#include "gamedata.h"

typedef struct Replacement {
std::string group;
std::string replacement;
} Replacement;

typedef struct ColorConCommand_s {
Color color;
ConCommand *command;
} ColorConCommand_t;

inline bool DataCompare(const BYTE* pData, const BYTE* bSig, const char* szMask) {
for (; *szMask; ++szMask, ++pData, ++bSig)
{
if (*szMask == 'x' && *pData != *bSig)
return false;
}

return (*szMask) == NULL;
}

inline DWORD FindPattern(DWORD dwAddress, DWORD dwSize, BYTE* pbSig, const char* szMask) {
for (DWORD i = NULL; i < dwSize; i++)
{
if (DataCompare((BYTE*)(dwAddress + i), pbSig, szMask))
return (DWORD)(dwAddress + i);
}

return 0;
}

inline DWORD SignatureScan(const char *moduleName, const char *signature, const char *mask) {
#if defined _WIN32
MODULEINFO clientModInfo;
const HMODULE clientModule = GetHandleOfModule(moduleName);
GetModuleInformation(GetCurrentProcess(), clientModule, &clientModInfo, sizeof(MODULEINFO));

return FindPattern((DWORD)clientModule, clientModInfo.SizeOfImage, (PBYTE)signature, mask);
#endif
}

inline void FindAndReplaceInString(std::string &str, const std::string &find, const std::string &replace) {
if (find.empty())
return;

size_t start_pos = 0;

while ((start_pos = str.find(find, start_pos)) != std::string::npos) {
str.replace(start_pos, find.length(), replace);
start_pos += replace.length();
}
}

inline float ChangeScale(float currentValue, float currentMin, float currentMax, float newMin, float newMax) {
float deltaScaler = ((newMax - newMin) / (currentMax - currentMin));
float newDelta = ((currentValue - currentMin) * deltaScaler);
float newValue = newMin + newDelta;

return newValue;
}

inline int ColorRangeRestrict(int color) {
if (color < 0) return 0;
else if (color > 255) return 255;
else return color;
}

inline bool IsInteger(const std::string &s) {
if (s.empty() || !isdigit(s[0])) return false;

char *p;
strtoull(s.c_str(), &p, 10);

return (*p == 0);
}

inline CSteamID ConvertTextToSteamID(std::string textID) {
if (IsInteger(textID)) {
uint64_t steamID = strtoull(textID.c_str(), nullptr, 10);

return CSteamID(steamID);
}

return CSteamID();
}

inline std::string ConvertTreeToString(std::vector<std::string> tree) {
std::stringstream ss;
std::string string;

for (auto iterator = tree.begin(); iterator != tree.end(); ++iterator) {
ss << ">";
ss << *iterator;
}

ss >> string;

return string;
}

#define PLUGIN_VERSION "0.23.0"
#define PRINT_TAG() ConColorMsg(Color(0, 153, 153, 255), "[StatusSpec] ")
135 changes: 48 additions & 87 deletions src/entities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,87 +10,26 @@

#include "entities.h"

#define RETRIEVE_OFFSET(offset, retrieve) \
if (!retrieve) { \
Warning("[StatusSpec] Offset %s is invalid!\n", #offset); \
return false; \
}
std::unordered_map<std::string, std::unordered_map<std::string, int>> Entities::classPropOffsets;

int Entities::pCTFPlayer__m_iClass = 0;
int Entities::pCTFPlayer__m_nPlayerCond = 0;
int Entities::pCTFPlayer___condition_bits = 0;
int Entities::pCTFPlayer__m_nPlayerCondEx = 0;
int Entities::pCTFPlayer__m_nPlayerCondEx2 = 0;
int Entities::pCTFPlayer__m_hActiveWeapon = 0;
int Entities::pCTFPlayer__m_hMyWeapons[MAX_WEAPONS] = { 0 };
int Entities::pCTFPlayer__m_iHealth = 0;
int Entities::pCEconEntity__m_hOwnerEntity = 0;
int Entities::pCEconEntity__m_iItemDefinitionIndex = 0;
int Entities::pCWeaponMedigun__m_bChargeRelease = 0;
int Entities::pCWeaponMedigun__m_nChargeResistType = 0;
int Entities::pCWeaponMedigun__m_flChargeLevel = 0;
int Entities::pCTFPlayerResource__m_iKillstreak[MAX_PLAYERS + 1] = { 0 };
int Entities::pCWeaponMedigun__m_bHealing = 0;
int Entities::pCWeaponMedigun__m_hHealingTarget = 0;
int Entities::pCTFPlayer__m_iKillStreak = 0;
int Entities::pCTFGrenadePipebombProjectile__m_iType = 0;
int Entities::pCTFGameRulesProxy__m_hRedKothTimer = 0;
int Entities::pCTFGameRulesProxy__m_hBlueKothTimer = 0;
int Entities::pCTFObjectiveResource__m_iTimerToShowInHUD = 0;
int Entities::pCTFObjectiveResource__m_iStopWatchTimer = 0;
int Entities::pCTFRagdoll__m_iPlayerIndex = 0;

bool Entities::PrepareOffsets() {
RETRIEVE_OFFSET(pCTFPlayer__m_iClass, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_iClass, 1, "m_iClass"));
RETRIEVE_OFFSET(pCTFPlayer__m_nPlayerCond, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_nPlayerCond, 1, "m_nPlayerCond"));
RETRIEVE_OFFSET(pCTFPlayer___condition_bits, GetClassPropOffset("CTFPlayer", pCTFPlayer___condition_bits, 1, "_condition_bits"));
RETRIEVE_OFFSET(pCTFPlayer__m_nPlayerCondEx, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_nPlayerCondEx, 1, "m_nPlayerCondEx"));
RETRIEVE_OFFSET(pCTFPlayer__m_nPlayerCondEx2, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_nPlayerCondEx2, 1, "m_nPlayerCondEx2"));
RETRIEVE_OFFSET(pCTFPlayer__m_hActiveWeapon, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_hActiveWeapon, 1, "m_hActiveWeapon"));
for (int i = 0; i < MAX_WEAPONS; i++) {
char *elementName = new char[4];
sprintf(elementName, "%03i", i);
RETRIEVE_OFFSET(pCTFPlayer__m_hMyWeapons[i], GetClassPropOffset("CTFPlayer", pCTFPlayer__m_hMyWeapons[i], 2, "m_hMyWeapons", elementName));
}
RETRIEVE_OFFSET(pCTFPlayer__m_iHealth, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_iHealth, 1, "m_iHealth"));
RETRIEVE_OFFSET(pCEconEntity__m_hOwnerEntity, GetClassPropOffset("CEconEntity", pCEconEntity__m_hOwnerEntity, 1, "m_hOwnerEntity"));
RETRIEVE_OFFSET(pCEconEntity__m_iItemDefinitionIndex, GetClassPropOffset("CEconEntity", pCEconEntity__m_iItemDefinitionIndex, 1, "m_iItemDefinitionIndex"));
RETRIEVE_OFFSET(pCWeaponMedigun__m_bChargeRelease, GetClassPropOffset("CWeaponMedigun", pCWeaponMedigun__m_bChargeRelease, 1, "m_bChargeRelease"));
RETRIEVE_OFFSET(pCWeaponMedigun__m_nChargeResistType, GetClassPropOffset("CWeaponMedigun", pCWeaponMedigun__m_nChargeResistType, 1, "m_nChargeResistType"));
RETRIEVE_OFFSET(pCWeaponMedigun__m_flChargeLevel, GetClassPropOffset("CWeaponMedigun", pCWeaponMedigun__m_flChargeLevel, 1, "m_flChargeLevel"));
for (int i = 0; i <= MAX_PLAYERS; i++) {
char *elementName = new char[4];
sprintf(elementName, "%03i", i);
RETRIEVE_OFFSET(pCTFPlayerResource__m_iKillstreak[i], GetClassPropOffset("CTFPlayerResource", pCTFPlayerResource__m_iKillstreak[i], 2, "m_iKillstreak", elementName));
bool Entities::RetrieveClassPropOffset(std::string className, std::vector<std::string> propertyTree) {
std::string propertyString = ConvertTreeToString(propertyTree);

if (classPropOffsets[className].find(propertyString) != classPropOffsets[className].end()) {
return true;
}
RETRIEVE_OFFSET(pCWeaponMedigun__m_bHealing, GetClassPropOffset("CWeaponMedigun", pCWeaponMedigun__m_bHealing, 1, "m_bHealing"));
RETRIEVE_OFFSET(pCWeaponMedigun__m_hHealingTarget, GetClassPropOffset("CWeaponMedigun", pCWeaponMedigun__m_hHealingTarget, 1, "m_hHealingTarget"));
RETRIEVE_OFFSET(pCTFPlayer__m_iKillStreak, GetClassPropOffset("CTFPlayer", pCTFPlayer__m_iKillStreak, 1, "m_iKillStreak"));
RETRIEVE_OFFSET(pCTFGrenadePipebombProjectile__m_iType, GetClassPropOffset("CTFGrenadePipebombProjectile", pCTFGrenadePipebombProjectile__m_iType, 1, "m_iType"));
RETRIEVE_OFFSET(pCTFGameRulesProxy__m_hRedKothTimer, GetClassPropOffset("CTFGameRulesProxy", pCTFGameRulesProxy__m_hRedKothTimer, 1, "m_hRedKothTimer"));
RETRIEVE_OFFSET(pCTFGameRulesProxy__m_hBlueKothTimer, GetClassPropOffset("CTFGameRulesProxy", pCTFGameRulesProxy__m_hBlueKothTimer, 1, "m_hBlueKothTimer"));
RETRIEVE_OFFSET(pCTFObjectiveResource__m_iTimerToShowInHUD, GetClassPropOffset("CTFObjectiveResource", pCTFObjectiveResource__m_iTimerToShowInHUD, 1, "m_iTimerToShowInHUD"));
RETRIEVE_OFFSET(pCTFObjectiveResource__m_iStopWatchTimer, GetClassPropOffset("CTFObjectiveResource", pCTFObjectiveResource__m_iStopWatchTimer, 1, "m_iStopWatchTimer"));
RETRIEVE_OFFSET(pCTFRagdoll__m_iPlayerIndex, GetClassPropOffset("CTFRagdoll", pCTFRagdoll__m_iPlayerIndex, 1, "m_iPlayerIndex"));

return true;
}

bool Entities::GetClassPropOffset(const char *className, int &offset, int depth, ...) {
ClientClass *cc = Interfaces::pClientDLL->GetAllClasses();

while (cc) {
if (Q_strcmp(cc->GetName(), className) == 0) {
if (className.compare(cc->GetName()) == 0) {
RecvTable *table = cc->m_pRecvTable;

offset = 0;
int offset = 0;
RecvProp *prop = nullptr;

if (table) {
va_list args;
va_start(args, depth);

for (int i = 0; i < depth; i++) {
for (auto iterator = propertyTree.begin(); iterator != propertyTree.end(); ++iterator) {
int subOffset = 0;

if (prop && prop->GetType() == DPT_DataTable) {
Expand All @@ -101,7 +40,7 @@ bool Entities::GetClassPropOffset(const char *className, int &offset, int depth,
return false;
}

if (GetSubProp(table, va_arg(args, const char *), prop, subOffset)) {
if (GetSubProp(table, iterator->c_str(), prop, subOffset)) {
offset += subOffset;
}
else {
Expand All @@ -111,7 +50,7 @@ bool Entities::GetClassPropOffset(const char *className, int &offset, int depth,
table = nullptr;
}

va_end(args);
classPropOffsets[className][propertyString] = offset;

return true;
}
Expand All @@ -122,6 +61,18 @@ bool Entities::GetClassPropOffset(const char *className, int &offset, int depth,
return false;
}

void *Entities::GetEntityProp(IClientEntity *entity, std::vector<std::string> propertyTree) {
std::string className = entity->GetClientClass()->GetName();

if (!RetrieveClassPropOffset(className, propertyTree)) {
throw invalid_class_prop(className.c_str());
}

std::string propertyString = ConvertTreeToString(propertyTree);

return (void *)((unsigned long)(entity)+(unsigned long)(classPropOffsets[className][propertyString]));
}

bool Entities::GetSubProp(RecvTable *table, const char *propName, RecvProp *&prop, int &offset) {
for (int i = 0; i < table->GetNumProps(); i++) {
offset = 0;
Expand All @@ -145,33 +96,43 @@ bool Entities::GetSubProp(RecvTable *table, const char *propName, RecvProp *&pro
return false;
}

inline bool CheckBaseclass(RecvTable *sTable, const char *baseclassDataTableName) {
if (strcmp(sTable->GetName(), baseclassDataTableName) == 0) {
bool Entities::CheckEntityBaseclass(IClientEntity *entity, std::string baseclass) {
ClientClass *clientClass = entity->GetClientClass();

if (clientClass) {
return CheckClassBaseclass(clientClass, baseclass);
}

return false;
}

bool Entities::CheckClassBaseclass(ClientClass *clientClass, std::string baseclass) {
RecvTable *sTable = clientClass->m_pRecvTable;

if (sTable) {
return CheckTableBaseclass(sTable, baseclass);
}

return false;
}

bool Entities::CheckTableBaseclass(RecvTable *sTable, std::string baseclass) {
if (std::string(sTable->GetName()).compare("DT_" + baseclass) == 0) {
return true;
}

for (int i = 0; i < sTable->GetNumProps(); i++) {
RecvProp *sProp = sTable->GetProp(i);

if (strcmp(sProp->GetName(), "baseclass") != 0) {
continue;
}

RecvTable *sChildTable = sProp->GetDataTable();
if (sChildTable) {
return CheckBaseclass(sChildTable, baseclassDataTableName);
return CheckTableBaseclass(sChildTable, baseclass);
}
}

return false;
}

bool Entities::CheckClassBaseclass(ClientClass *clientClass, const char *baseclassDataTableName) {
RecvTable *sTable = clientClass->m_pRecvTable;

if (sTable) {
return CheckBaseclass(sTable, baseclassDataTableName);
}

return false;
}
Loading

0 comments on commit 753b52c

Please sign in to comment.