Last active
September 2, 2019 06:10
-
-
Save nosoop/8970c545797dd9592b2b140a7ae1f583 to your computer and use it in GitHub Desktop.
Some code to pull properties out of entities in a nice-looking way with a SourceMod extension
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "re.h" | |
#include <sm_stringhashmap.h> | |
template <typename T> | |
inline T* sendprop_ptr(const void* pEntity, const char* classname, const char* prop) { | |
sm_sendprop_info_t info; | |
if (!gamehelpers->FindSendPropInfo(classname, prop, &info)) { | |
return nullptr; | |
} | |
return offset_ptr<T>(pEntity, info.actual_offset); | |
} | |
template <typename T> | |
inline T sendprop_value(const void* pEntity, const char* classname, const char* prop, | |
T defaultValue = T()) { | |
T* entprop = sendprop_ptr<T>(pEntity, classname, prop); | |
return entprop? *entprop : defaultValue; | |
} | |
template <typename T> | |
inline T* dataprop_ptr(const CBaseEntity* pEntity, const char* prop) { | |
auto pMap = gamehelpers->GetDataMap(const_cast<CBaseEntity*>(pEntity)); | |
sm_datatable_info_t info; | |
if (!gamehelpers->FindDataMapInfo(pMap, prop, &info)) { | |
return nullptr; | |
} | |
return offset_ptr<T>(pEntity, info.actual_offset); | |
} | |
template <typename T> | |
inline T dataprop_value(const CBaseEntity* pEntity, const char* prop, T defaultValue = T()) { | |
T* entprop = dataprop_ptr<T>(pEntity, prop); | |
return entprop? *entprop : defaultValue; | |
} | |
/** | |
* Implements a per-class sendprop accessor. | |
*/ | |
template <typename T> | |
class SendPropGetter { | |
public: | |
using SendPropOffsetMap = StringHashMap<size_t>; | |
SendPropGetter(const char* szNetClass) : m_szNetClass{szNetClass}, map{} {}; | |
template <typename M> | |
M GetValue(const T* pEntity, const char* prop, M defaultValue = M()) const { | |
M* value = this->GetPointer<M>(pEntity, prop); | |
return value? *value : defaultValue; | |
} | |
template <typename M> | |
M* GetPointer(const T* pEntity, const char* prop) const { | |
size_t offset; | |
return this->Lookup(prop, offset)? offset_ptr<M>(pEntity, offset) : nullptr; | |
} | |
private: | |
bool Lookup(const char* prop, size_t &offset) const { | |
SendPropOffsetMap::Insert p = map.findForAdd(prop); | |
if (!p.found()) { | |
sm_sendprop_info_t info; | |
if (!gamehelpers->FindSendPropInfo(m_szNetClass, prop, &info)) { | |
return false; | |
} | |
map.add(p, prop); | |
p->value = info.actual_offset; | |
} | |
offset = p->value; | |
return true; | |
} | |
const char* m_szNetClass; | |
mutable SendPropOffsetMap map; | |
}; | |
/** | |
* Implements a sendprop accessor for the given class. Note that the member still has to be | |
* initialized with the game's classname. | |
*/ | |
template <typename T> | |
class ISendProp | |
{ | |
public: | |
template <typename M> | |
M GetSendProp(const char* prop, M defaultValue = M()) const { | |
return ISendProp<T>::sendprops.GetValue(static_cast<const T*>(this), prop, defaultValue); | |
} | |
template <typename M> | |
M* GetSendPropPtr(const char* prop) const { | |
return ISendProp<T>::sendprops.template GetPointer<M>(static_cast<const T*>(this), prop); | |
} | |
private: | |
static const SendPropGetter<T> sendprops; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Utility macros and functions for reverse engineered classes. | |
*/ | |
#pragma once | |
#define DECL_STUB_CLASS(TYPE, SIZE) class TYPE {\ | |
private: \ | |
uint8_t bytes[SIZE]; \ | |
} | |
#define DECL_STUB_SUBCLASS(TYPE, SUPERCLASS, SIZE) class TYPE : public SUPERCLASS {\ | |
private: \ | |
uint8_t bytes[SIZE]; \ | |
} | |
// https://stackoverflow.com/a/1597129 | |
#define TOKENPASTE(x, y) x ## y | |
#define TOKENPASTE2(x, y) TOKENPASTE(x, y) | |
#define PAD(_size_) uint8_t TOKENPASTE2(m_unk_, __LINE__)[_size_] | |
#define SIZE_CHECK(_t, _size) static_assert(sizeof(_t) == _size, "sizeof(" #_t ") == " #_size) | |
#define DEBUG_SIZE(_t) char (*__kaboom)[sizeof(_t)] = 1 | |
// https://stackoverflow.com/a/20141143 | |
template<typename T, typename U> constexpr size_t offsetOf(U T::*member) { | |
return (char*)&((T*)nullptr->*member) - (char*)nullptr; | |
} | |
/** | |
* Utility function that returns a pointer of type T from a base address plus offset. | |
* Used to access non-pointer class members, or to get pointers to class values. | |
*/ | |
template<typename T> | |
inline T* offset_ptr(const void* ptr, size_t offset) { | |
return (T*) ((unsigned char*) ptr + offset); | |
} | |
/** | |
* Utility function that returns a value of type T from a base address plus offset. | |
* Same as dereferencing the result of offset_ptr. Used to read values from offsets. | |
*/ | |
template<typename T> | |
inline T offset_value(const void* ptr, size_t offset) { | |
return *offset_ptr<T>(ptr, offset); | |
} | |
/** | |
* Utility function that does a placement new, allocating enough space to hold an instance of | |
* class T (assuming the class definition of T has the same size as the server's | |
* implementation). | |
*/ | |
template <class T> | |
inline T* alloc_raw_class() { | |
return reinterpret_cast<T*>(::operator new(sizeof(T))); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "entprops.h" | |
// implement sendprops for the given class | |
class CCaptureZone : public ISendProp<CCaptureZone> {}; | |
// actually implement the sendprop accessor | |
template<> | |
const SendPropGetter<CCaptureZone> ISendProp<CCaptureZone>::sendprops("CCaptureZone"); | |
// you can do something like `auto disabled = reinterpret_cast<CCaptureZone*>(ptr)->GetSendProp<bool>("m_bDisabled");` | |
// of course no typechecks are done, enjoy your footguns |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment