S K I N C H 🅰️ 🆖 E R wow!

This commit is contained in:
nullifiedcat 2017-05-05 22:36:00 +03:00
parent 9de7313c48
commit 348719ae46
3 changed files with 215 additions and 57 deletions

View File

@ -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 };
}}}

View File

@ -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();

View File

@ -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");