S K I N C H 🅰️ 🆖 E R wow!
This commit is contained in:
parent
9de7313c48
commit
348719ae46
@ -23,7 +23,6 @@ ItemSchemaPtr_t GetItemSchema(void) {
|
||||
if (!ItemSystem) {
|
||||
ItemSystem = (ItemSystem_t)gSignatures.GetClientSignature((char*)sig_GetItemSchema);
|
||||
}
|
||||
logging::Info("ItemSystem: 0x%08x 0x%08x", ItemSystem, ItemSystem());
|
||||
return (void*)((uint32_t)(ItemSystem()) + 4);
|
||||
}
|
||||
|
||||
@ -32,6 +31,17 @@ CAttribute::CAttribute(uint16_t iAttributeDefinitionIndex, float flValue) {
|
||||
value = flValue;
|
||||
}
|
||||
|
||||
|
||||
float CAttributeList::GetAttribute(int defindex) {
|
||||
for (int i = 0; i < m_Attributes.Count(); i++) {
|
||||
const auto& a = m_Attributes[i];
|
||||
if (a.defidx == defindex) {
|
||||
return a.value;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void CAttributeList::RemoveAttribute(int index) {
|
||||
for (int i = 0; i < m_Attributes.Count(); i++) {
|
||||
const auto& a = m_Attributes[i];
|
||||
@ -45,11 +55,10 @@ void CAttributeList::RemoveAttribute(int index) {
|
||||
CAttributeList::CAttributeList() {}
|
||||
|
||||
void CAttributeList::SetAttribute(int index, float value) {
|
||||
ItemSchemaPtr_t schema = GetItemSchema();
|
||||
logging::Info("Schema: 0x%08x", schema);
|
||||
static ItemSchemaPtr_t schema = GetItemSchema();
|
||||
AttributeDefinitionPtr_t attrib = GetAttributeDefinitionFn(schema, index);
|
||||
logging::Info("Attrib: 0x%08x", attrib);
|
||||
SetRuntimeAttributeValueFn(this, attrib, value);
|
||||
// The code below actually is unused now - but I'll keep it just in case!
|
||||
// Let's check if attribute exists already. We don't want dupes.
|
||||
/*for (int i = 0; i < m_Attributes.Count(); i++) {
|
||||
auto& a = m_Attributes[i];
|
||||
@ -62,33 +71,64 @@ void CAttributeList::SetAttribute(int index, float value) {
|
||||
if (m_Attributes.Count() > 14)
|
||||
return;
|
||||
|
||||
//m_Attributes.m_Memory.m_nGrowSize = -1;
|
||||
//logging::Info("0x%08x 0x%08x 0x%08x", m_Attributes.m_Memory.m_nAllocationCount, m_Attributes.m_Memory.m_nGrowSize, m_Attributes.m_Memory.m_pMemory);
|
||||
//m_Attributes.m_Memory.SetExternalBuffer(m_Attributes.m_Memory.Base(), 15);
|
||||
CAttribute attr( index, value );
|
||||
m_Attributes.AddToTail(attr);*/
|
||||
m_Attributes.AddToTail({ index, value });
|
||||
*/
|
||||
}
|
||||
|
||||
static CatVar enabled(CV_SWITCH, "skinchanger", "0", "Skin Changer");
|
||||
static CatCommand set_attr("skinchanger_set", "Set Attribute", [](const CCommand& args) {
|
||||
unsigned attrid = strtoul(args.Arg(1), nullptr, 10);
|
||||
unsigned attrv = strtoul(args.Arg(2), nullptr, 10);
|
||||
float attrv = strtof(args.Arg(2), nullptr);
|
||||
GetModifier(CE_INT(LOCAL_W, netvar.iItemDefinitionIndex)).Set(attrid, attrv);
|
||||
InvalidateCookies();
|
||||
InvalidateCookie();
|
||||
});
|
||||
static CatCommand remove_attr("skinchanger_remove", "Remove attribute", [](const CCommand& args) {
|
||||
unsigned attrid = strtoul(args.Arg(1), nullptr, 10);
|
||||
GetModifier(CE_INT(LOCAL_W, netvar.iItemDefinitionIndex)).Remove(attrid);
|
||||
InvalidateCookie();
|
||||
});
|
||||
static CatCommand set_redirect("skinchanger_redirect", "Set Redirect", [](const CCommand& args) {
|
||||
unsigned redirect = strtoul(args.Arg(1), nullptr, 10);
|
||||
GetModifier(CE_INT(LOCAL_W, netvar.iItemDefinitionIndex)).defidx_redirect = redirect;
|
||||
InvalidateCookies();
|
||||
InvalidateCookie();
|
||||
});
|
||||
static CatCommand dump_attrs("skinchanger_debug_attrs", "Dump attributes", []() {
|
||||
CAttributeList* list = CE_VAR(LOCAL_W, netvar.AttributeList, CAttributeList*);
|
||||
CAttributeList* list = (CAttributeList*)((uintptr_t)(RAW_ENT(LOCAL_W)) + netvar.AttributeList);
|
||||
logging::Info("ATTRIBUTE LIST: %i", list->m_Attributes.Size());
|
||||
for (int i = 0; i < 15; i++) {
|
||||
for (int i = 0; i < list->m_Attributes.Size(); i++) {
|
||||
logging::Info("%i %.2f", list->m_Attributes[i].defidx, list->m_Attributes[i].value);
|
||||
}
|
||||
});
|
||||
static CatCommand invalidate_cookies("skinchanger_invalidate_cookies", "Invalidate Cookies", InvalidateCookies);
|
||||
|
||||
static CatCommand list_redirects("skinchanger_redirect_list", "Dump redirects", []() {
|
||||
for (const auto& mod : modifier_map) {
|
||||
if (mod.second.defidx_redirect) {
|
||||
logging::Info("%d -> %d", mod.first, mod.second.defidx_redirect);
|
||||
}
|
||||
}
|
||||
});
|
||||
static CatCommand save("skinchanger_save", "Save", [](const CCommand& args) {
|
||||
std::string filename = "skinchanger";
|
||||
if (args.ArgC() > 1) {
|
||||
filename = args.Arg(1);
|
||||
}
|
||||
Save(filename);
|
||||
});
|
||||
static CatCommand load("skinchanger_load", "Load", [](const CCommand& args) {
|
||||
std::string filename = "skinchanger";
|
||||
if (args.ArgC() > 1) {
|
||||
filename = args.Arg(1);
|
||||
}
|
||||
Load(filename);
|
||||
});
|
||||
static CatCommand remove_redirect("skinchanger_remove_redirect", "Remove redirect", [](const CCommand& args) {
|
||||
unsigned redirectid = strtoul(args.Arg(1), nullptr, 10);
|
||||
GetModifier(redirectid).defidx_redirect = 0;
|
||||
logging::Info("Redirect removed");
|
||||
InvalidateCookie();
|
||||
});
|
||||
|
||||
static CatCommand invalidate_cookies("skinchanger_bite_cookie", "Bite Cookie", InvalidateCookie);
|
||||
|
||||
void FrameStageNotify(int stage) {
|
||||
if (!enabled) return;
|
||||
@ -105,21 +145,115 @@ void FrameStageNotify(int stage) {
|
||||
int handle = CE_INT(g_pLocalPlayer->entity, netvar.hActiveWeapon);
|
||||
int eid = handle & 0xFFF;
|
||||
IClientEntity* entity = g_IEntityList->GetClientEntity(eid);
|
||||
GetModifier(NET_INT(entity, netvar.iItemDefinitionIndex)).Apply(eid);
|
||||
/*if (!GetCookie(weapon->m_IDX).Check()) {
|
||||
logging::Info("Cookie bad for %i", weapon->m_IDX); // FIXME DEBUG LOGS!
|
||||
GetModifier(CE_INT(weapon, netvar.iItemDefinitionIndex)).Apply(weapon->m_IDX);
|
||||
GetCookie(weapon->m_IDX).Update(weapon->m_IDX);
|
||||
}*/
|
||||
if (!entity || entity->IsDormant()) return;
|
||||
static IClientEntity* last_weapon_out = nullptr;
|
||||
if ((last_weapon_out != entity) || !cookie.Check()) {
|
||||
GetModifier(NET_INT(entity, netvar.iItemDefinitionIndex)).Apply(eid);
|
||||
cookie.Update(eid);
|
||||
}
|
||||
last_weapon_out = entity;
|
||||
}
|
||||
|
||||
static CatVar show_debug_info(CV_SWITCH, "skinchanger_debug", "1", "Debug Skinchanger");
|
||||
|
||||
void PaintTraverse() {
|
||||
if (!enabled) return;
|
||||
if (CE_GOOD(LOCAL_W))
|
||||
if (!show_debug_info) return;
|
||||
if (CE_GOOD(LOCAL_W)) {
|
||||
AddSideString(format("dIDX: ", CE_INT(LOCAL_W, netvar.iItemDefinitionIndex)));
|
||||
CAttributeList* list = (CAttributeList*)((uintptr_t)(RAW_ENT(LOCAL_W)) + netvar.AttributeList);
|
||||
for (int i = 0; i < list->m_Attributes.Size(); i++) {
|
||||
AddSideString(format('[', i, "] ", list->m_Attributes[i].defidx, ": ", list->m_Attributes[i].value));
|
||||
}
|
||||
}
|
||||
//
|
||||
// Debug info?
|
||||
}
|
||||
|
||||
#define BINARY_FILE_WRITE(handle, data) handle.write(reinterpret_cast<const char*>(&data), sizeof(data))
|
||||
#define BINARY_FILE_READ(handle, data) handle.read(reinterpret_cast<char*>(&data), sizeof(data))
|
||||
|
||||
void Save(std::string filename) {
|
||||
uid_t uid = geteuid();
|
||||
passwd* pw = getpwuid(uid);
|
||||
if (!pw) {
|
||||
logging::Info("Couldn't get username!");
|
||||
return;
|
||||
}
|
||||
std::string name(pw->pw_name);
|
||||
DIR* cathook_directory = opendir(strfmt("/home/%s/.cathook", pw->pw_name));
|
||||
if (!cathook_directory) {
|
||||
logging::Info(".cathook directory doesn't exist, creating one!");
|
||||
mkdir(strfmt("/home/%s/.cathook", pw->pw_name), S_IRWXU | S_IRWXG);
|
||||
} else closedir(cathook_directory);
|
||||
try {
|
||||
std::ofstream file("/home/" + name + "/.cathook/" + filename, std::ios::out | std::ios::binary);
|
||||
BINARY_FILE_WRITE(file, SERIALIZE_VERSION);
|
||||
size_t size = modifier_map.size();
|
||||
BINARY_FILE_WRITE(file, size);
|
||||
for (const auto& item : modifier_map) {
|
||||
BINARY_FILE_WRITE(file, item.first);
|
||||
// modifier data isn't a POD (it contains a vector), we can't BINARY_WRITE it completely.
|
||||
BINARY_FILE_WRITE(file, item.second.defidx_redirect);
|
||||
const auto& modifiers = item.second.modifiers;
|
||||
size_t modifier_count = modifiers.size();
|
||||
BINARY_FILE_WRITE(file, modifier_count);
|
||||
// this code is a bit tricky - I'm treating vector as an array
|
||||
if (modifier_count) {
|
||||
file.write(reinterpret_cast<const char*>(modifiers.data()), modifier_count * sizeof(attribute_s));
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
logging::Info("Writing successful");
|
||||
} catch (std::exception& e) {
|
||||
logging::Info("Writing unsuccessful: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void Load(std::string filename) {
|
||||
uid_t uid = geteuid();
|
||||
passwd* pw = getpwuid(uid);
|
||||
if (!pw) {
|
||||
logging::Info("Couldn't get username!");
|
||||
return;
|
||||
}
|
||||
std::string name(pw->pw_name);
|
||||
DIR* cathook_directory = opendir(strfmt("/home/%s/.cathook", pw->pw_name));
|
||||
if (!cathook_directory) {
|
||||
logging::Info(".cathook directory doesn't exist, creating one!");
|
||||
mkdir(strfmt("/home/%s/.cathook", pw->pw_name), S_IRWXU | S_IRWXG);
|
||||
} else closedir(cathook_directory);
|
||||
try {
|
||||
std::ifstream file("/home/" + name + "/.cathook/" + filename, std::ios::in | std::ios::binary);
|
||||
unsigned file_serialize = 0;
|
||||
BINARY_FILE_READ(file, file_serialize);
|
||||
if (file_serialize != SERIALIZE_VERSION) {
|
||||
logging::Info("Outdated/corrupted SkinChanger file! Cannot load this.");
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
size_t size = 0;
|
||||
BINARY_FILE_READ(file, size);
|
||||
logging::Info("Reading %i entries...", size);
|
||||
modifier_map.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int defindex;
|
||||
BINARY_FILE_READ(file, defindex);
|
||||
size_t count;
|
||||
def_attribute_modifier modifier;
|
||||
BINARY_FILE_READ(file, modifier.defidx_redirect);
|
||||
BINARY_FILE_READ(file, count);
|
||||
modifier.modifiers.resize(count);
|
||||
file.read(reinterpret_cast<char*>(modifier.modifiers.data()), sizeof(attribute_s) * count);
|
||||
modifier_map.insert(std::make_pair(defindex, std::move(modifier)));
|
||||
}
|
||||
file.close();
|
||||
logging::Info("Reading successful! Result: %i entries.", modifier_map.size());
|
||||
} catch (std::exception& e) {
|
||||
logging::Info("Reading unsuccessful: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void def_attribute_modifier::Set(int id, float value) {
|
||||
for (auto& i : modifiers) {
|
||||
if (i.defidx == id) {
|
||||
@ -127,29 +261,25 @@ void def_attribute_modifier::Set(int id, float value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
attribute_s& attr = modifiers.at(first_free_mod);
|
||||
first_free_mod++;
|
||||
attr.defidx = id;
|
||||
attr.value = value;
|
||||
logging::Info("new attr: %i %.2f %i", attr.defidx, attr.value, first_free_mod);
|
||||
}
|
||||
|
||||
void InvalidateCookies() {
|
||||
logging::Info("All cookies invalidated!"); // FIXME DEBUG LOGS!
|
||||
for (auto& cookie : cookie_map) {
|
||||
cookie.second.valid = false;
|
||||
if (modifiers.size() > 13) {
|
||||
logging::Info("Woah there, that's too many! Remove some.");
|
||||
return;
|
||||
}
|
||||
modifiers.push_back(attribute_s { id, value });
|
||||
logging::Info("Added new attribute: %i %.2f (%i)", id, value, modifiers.size());
|
||||
}
|
||||
|
||||
patched_weapon_cookie::patched_weapon_cookie(int entity) {
|
||||
Update(entity);
|
||||
void InvalidateCookie() {
|
||||
cookie.valid = false;
|
||||
}
|
||||
|
||||
patched_weapon_cookie::patched_weapon_cookie(int entity) {}
|
||||
|
||||
void patched_weapon_cookie::Update(int entity) {
|
||||
IClientEntity* ent = g_IEntityList->GetClientEntity(entity);
|
||||
if (!ent || ent->IsDormant()) return;
|
||||
logging::Info("Updating cookie for %i", entity); // FIXME DEBUG LOGS!
|
||||
CAttributeList* list = NET_VAR(ent, 0x9c0, CAttributeList*);
|
||||
CAttributeList* list = (CAttributeList*)((uintptr_t)ent + netvar.AttributeList);
|
||||
attrs = list->m_Attributes.Size();
|
||||
eidx = entity;
|
||||
defidx = NET_INT(ent, netvar.iItemDefinitionIndex);
|
||||
@ -161,32 +291,40 @@ bool patched_weapon_cookie::Check() {
|
||||
if (!valid) return false;
|
||||
IClientEntity* ent = g_IEntityList->GetClientEntity(eidx);
|
||||
if (!ent || ent->IsDormant()) return false;
|
||||
CAttributeList* list = NET_VAR(ent, 0x9c0, CAttributeList*);
|
||||
CAttributeList* list = (CAttributeList*)((uintptr_t)ent + netvar.AttributeList);
|
||||
if (attrs != list->m_Attributes.Size()) return false;
|
||||
if (eclass != ent->GetClientClass()->m_ClassID) return false;
|
||||
if (defidx != NET_INT(ent, netvar.iItemDefinitionIndex)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void def_attribute_modifier::Remove(int id) {
|
||||
auto it = modifiers.begin();
|
||||
while (it != modifiers.end()) {
|
||||
if ((*it).defidx == id) {
|
||||
it = modifiers.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void def_attribute_modifier::Apply(int entity) {
|
||||
IClientEntity* ent = g_IEntityList->GetClientEntity(entity);
|
||||
if (!ent) return;
|
||||
//logging::Info("Applying modifiers for %i %i %i", entity, NET_INT(ent, netvar.iItemDefinitionIndex), defidx_redirect);
|
||||
if (defidx_redirect && NET_INT(ent, netvar.iItemDefinitionIndex) != defidx_redirect) {
|
||||
NET_INT(ent, netvar.iItemDefinitionIndex) = defidx_redirect;
|
||||
logging::Info("Updated DefIDX to %i", NET_INT(ent, netvar.iItemDefinitionIndex));
|
||||
GetCookie(entity).valid = false;
|
||||
logging::Info("Redirect -> %i", NET_INT(ent, netvar.iItemDefinitionIndex));
|
||||
GetModifier(defidx_redirect).Apply(entity);
|
||||
return;
|
||||
}
|
||||
CAttributeList* list = NET_VAR(ent, netvar.AttributeList, CAttributeList*);
|
||||
//::Info("Attribute list: 0x%08x 0x%08x 0x%08x 0x%08x", 0x9c0, ent, list, (uint32_t)list - (uint32_t)ent);
|
||||
list->m_Attributes.m_Size = list->m_Attributes.Size();
|
||||
//logging::Info("Length: %i", list->m_Attributes.m_Size);
|
||||
//logging::Info("Base: 0x%08x", list->m_Attributes.Base());
|
||||
CAttributeList* list = (CAttributeList*)((uintptr_t)ent + netvar.AttributeList);
|
||||
for (const auto& mod : modifiers) {
|
||||
if (mod.defidx) {
|
||||
//logging::Info("Setting %i to %.2f", mod.defidx, mod.value); // FIXME DEBUG LOGS!
|
||||
list->SetAttribute(mod.defidx, mod.value);
|
||||
//if (mod.value)
|
||||
list->SetAttribute(mod.defidx, mod.value);
|
||||
//else
|
||||
// list->RemoveAttribute(mod.defidx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -200,16 +338,19 @@ def_attribute_modifier& GetModifier(int idx) {
|
||||
}
|
||||
}
|
||||
|
||||
patched_weapon_cookie& GetCookie(int idx) {
|
||||
/*patched_weapon_cookie& GetCookie(int idx) {
|
||||
try {
|
||||
return cookie_map.at(idx);
|
||||
} catch (std::out_of_range& oor) {
|
||||
cookie_map.emplace(idx, patched_weapon_cookie{idx});
|
||||
return cookie_map.at(idx);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// A map that maps an Item Definition Index to a modifier
|
||||
std::unordered_map<int, def_attribute_modifier> modifier_map {};
|
||||
std::unordered_map<int, patched_weapon_cookie> cookie_map {};
|
||||
// A map that maps an Entity Index to a cookie
|
||||
//std::unordered_map<int, patched_weapon_cookie> cookie_map {};
|
||||
patched_weapon_cookie cookie { 0 };
|
||||
|
||||
}}}
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
class CAttributeList {
|
||||
public:
|
||||
CAttributeList();
|
||||
float GetAttribute(int defindex);
|
||||
void SetAttribute(int index, float value);
|
||||
void RemoveAttribute(int index);
|
||||
public:
|
||||
@ -66,7 +67,8 @@ enum class Attributes {
|
||||
is_australium_item = 2027,
|
||||
item_style_override = 542,
|
||||
sheen = 2014,
|
||||
killstreak_tier = 2025
|
||||
killstreak_tier = 2025,
|
||||
set_item_texture_wear = 725
|
||||
};
|
||||
|
||||
enum class UnusualEffects {
|
||||
@ -76,6 +78,16 @@ enum class UnusualEffects {
|
||||
ENERGY_ORB
|
||||
};
|
||||
|
||||
enum class Sheens {
|
||||
TEAM_SHINE = 1,
|
||||
DEADLY_DAFFODIL,
|
||||
MANNDARIN,
|
||||
MEAN_GREEN,
|
||||
AGONIZING_EMERALD,
|
||||
VILLAINOUS_VIOLET,
|
||||
HOT_ROD
|
||||
};
|
||||
|
||||
struct patched_weapon_cookie {
|
||||
patched_weapon_cookie(int entity);
|
||||
void Update(int entity);
|
||||
@ -91,19 +103,24 @@ public:
|
||||
struct def_attribute_modifier {
|
||||
void Apply(int entity);
|
||||
void Set(int id, float value);
|
||||
void Remove(int id);
|
||||
int defidx { 0 };
|
||||
int defidx_redirect { 0 };
|
||||
std::array<attribute_s, 15> modifiers { attribute_s{ 0, 0 } };
|
||||
int first_free_mod { 0 };
|
||||
std::vector<attribute_s> modifiers { };
|
||||
};
|
||||
|
||||
extern std::unordered_map<int, def_attribute_modifier> modifier_map;
|
||||
extern std::unordered_map<int, patched_weapon_cookie> cookie_map;
|
||||
extern patched_weapon_cookie cookie;
|
||||
//extern std::unordered_map<int, patched_weapon_cookie> cookie_map;
|
||||
|
||||
def_attribute_modifier& GetModifier(int idx);
|
||||
patched_weapon_cookie& GetCookie(int idx);
|
||||
//patched_weapon_cookie& GetCookie(int idx);
|
||||
|
||||
void InvalidateCookies();
|
||||
constexpr unsigned SERIALIZE_VERSION = 1;
|
||||
void Save(std::string filename);
|
||||
void Load(std::string filename);
|
||||
|
||||
void InvalidateCookie();
|
||||
void FrameStageNotify(int stage);
|
||||
void PaintTraverse();
|
||||
|
||||
|
@ -30,7 +30,7 @@ void NetVars::Init() {
|
||||
//this->flReloadPriorNextFire = gNetvars.get_offset("DT_TFWeaponBase", "LocalActiveTFWeaponData", "m_flReloadPriorNextFire");
|
||||
//this->flObservedCritChance = gNetvars.get_offset("DT_TFWeaponBase", "LocalActiveTFWeaponData", "m_flObservedCritChance");
|
||||
this->iItemDefinitionIndex = gNetvars.get_offset("DT_EconEntity", "m_AttributeManager", "m_Item", "m_iItemDefinitionIndex");
|
||||
this->AttributeList = gNetvars.get_offset("DT_EconEntity", "m_AttributeManager", "m_Item", "m_AttributeList") + 8; // hmmm
|
||||
this->AttributeList = gNetvars.get_offset("DT_EconEntity", "m_AttributeManager", "m_Item", "m_AttributeList"); // hmmm
|
||||
this->flChargeBeginTime = gNetvars.get_offset("DT_WeaponPipebombLauncher", "PipebombLauncherLocalData", "m_flChargeBeginTime");
|
||||
this->flLastFireTime = gNetvars.get_offset("DT_TFWeaponBase", "LocalActiveTFWeaponData", "m_flLastFireTime");
|
||||
this->bDistributed = gNetvars.get_offset("DT_CurrencyPack", "m_bDistributed");
|
||||
|
Reference in New Issue
Block a user