diff --git a/src/hacks/FollowBot.cpp b/src/hacks/FollowBot.cpp index eea5946c..b52df27b 100644 --- a/src/hacks/FollowBot.cpp +++ b/src/hacks/FollowBot.cpp @@ -5,12 +5,13 @@ * Author: nullifiedcat */ -#ifdef IPC_ENABLED #include "FollowBot.h" #include "../common.h" +#ifdef IPC_ENABLED + namespace hacks { namespace shared { namespace followbot { unsigned follow_steamid { 0 }; diff --git a/src/hacks/SkinChanger.cpp b/src/hacks/SkinChanger.cpp new file mode 100644 index 00000000..3e10e829 --- /dev/null +++ b/src/hacks/SkinChanger.cpp @@ -0,0 +1,142 @@ +/* + * SkinChanger.cpp + * + * Created on: May 4, 2017 + * Author: nullifiedcat + */ + +#include "SkinChanger.hpp" + +namespace hacks { namespace tf2 { namespace skinchanger { + +CAttribute::CAttribute(uint16_t iAttributeDefinitionIndex, float flValue) { + data.defidx = iAttributeDefinitionIndex; + data.value = flValue; +} + +void CAttributeList::RemoveAttribute(int index) { + for (int i = 0; i < m_Attributes.Count(); i++) { + const auto& a = m_Attributes[i]; + if (a.data.defidx == index) { + m_Attributes.Remove(i); + return; + } + } +} + +void CAttributeList::SetAttribute(int index, float value) { + // 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]; + if (a.data.defidx == index) { + a.data.value = value; + return; + } + } + + if (m_Attributes.Count() > 14) + return; + + m_Attributes.AddToTail(CAttribute { 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); + GetModifier(LOCAL_W->m_IDX).Set(attrid, attrv); + InvalidateCookies(); +}); + +void FrameStageNotify(int stage) { + if (!enabled) return; + CachedEntity* weapon = LOCAL_W; + if (CE_BAD(weapon)) return; + 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); + } +} + +void PaintTraverse() { + if (!enabled) return; + // Debug info? +} + +void def_attribute_modifier::Set(int id, float value) { + for (auto& i : modifiers) { + if (i.defidx == id) { + i.value = value; + return; + } + } + attribute_s& attr = modifiers.at(modifiers.size()); + attr.defidx = id; + attr.value = value; +} + +void InvalidateCookies() { + logging::Info("All cookies invalidated!"); // FIXME DEBUG LOGS! + for (auto& cookie : cookie_map) { + cookie.second.valid = false; + } +} + +patched_weapon_cookie::patched_weapon_cookie(int entity) { + Update(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! + eidx = entity; + defidx = NET_INT(ent, netvar.iItemDefinitionIndex); + eclass = ent->GetClientClass()->m_ClassID; + valid = true; +} + +bool patched_weapon_cookie::Check() { + if (!valid) return false; + IClientEntity* ent = g_IEntityList->GetClientEntity(eidx); + if (!ent || ent->IsDormant()) return false; + if (eclass != ent->GetClientClass()->m_ClassID) return false; + if (defidx != NET_INT(ent, netvar.iItemDefinitionIndex)) return false; +} + +void def_attribute_modifier::Apply(int entity) { + IClientEntity* ent = g_IEntityList->GetClientEntity(entity); + if (!ent || ent->IsDormant()) return; + CAttributeList* list = NET_VAR(ent, netvar.AttributeList, CAttributeList*); + logging::Info("Applying modifiers for %i", entity); + 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); + } + } +} + +def_attribute_modifier& GetModifier(int idx) { + try { + return modifier_map.at(idx); + } catch (std::out_of_range& oor) { + modifier_map.emplace(idx, def_attribute_modifier{}); + return modifier_map.at(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); + } +} + +std::unordered_map modifier_map {}; +std::unordered_map cookie_map {}; + +}}} diff --git a/src/hacks/SkinChanger.hpp b/src/hacks/SkinChanger.hpp new file mode 100644 index 00000000..149152c3 --- /dev/null +++ b/src/hacks/SkinChanger.hpp @@ -0,0 +1,87 @@ +/* + * SkinChanger.hpp + * + * Created on: May 4, 2017 + * Author: nullifiedcat + */ + +#ifndef HACKS_SKINCHANGER_HPP_ +#define HACKS_SKINCHANGER_HPP_ + +#include "../common.h" + +namespace hacks { namespace tf2 { namespace skinchanger { + +// TOTALLY NOT A PASTE. +// Seriously tho, it's modified at least. +// Credits: blackfire62 + +struct attribute_s { + uint16_t defidx; + float value; +}; + +class CAttribute { +public: + CAttribute(uint16_t iAttributeDefinitionIndex, float flValue); +public: + uint32_t pad00; + attribute_s data; + uint32_t pad01; +}; + +class CAttributeList { +public: + void SetAttribute(int index, float value); + void RemoveAttribute(int index); +public: + uint32_t pad00; + CUtlVector> m_Attributes; +}; + +enum class Attributes { + loot_rarity = 2022, + is_australium_item = 2027, + item_style_override = 542, + sheen = 2014, + killstreak_tier = 2025 +}; + +enum class UnusualEffects { + HOT = 701, + ISOTOPE, + COOL, + ENERGY_ORB +}; + +struct patched_weapon_cookie { + patched_weapon_cookie(int entity); + void Update(int entity); + bool Check(); +public: + int eidx { 0 }; + int defidx { 0 }; + int eclass { 0 }; + bool valid { false }; +}; + +struct def_attribute_modifier { + void Apply(int entity); + void Set(int id, float value); + int defidx { 0 }; + std::array modifiers { attribute_s{ 0, 0 } }; +}; + +extern std::unordered_map modifier_map; +extern std::unordered_map cookie_map; + +def_attribute_modifier& GetModifier(int idx); +patched_weapon_cookie& GetCookie(int idx); + +void InvalidateCookies(); +void FrameStageNotify(int stage); +void PaintTraverse(); + +}}} + +#endif /* HACKS_SKINCHANGER_HPP_ */ diff --git a/src/hacks/hacklist.h b/src/hacks/hacklist.h index fe453563..0f8586a3 100644 --- a/src/hacks/hacklist.h +++ b/src/hacks/hacklist.h @@ -24,6 +24,7 @@ #include "Trigger.h" #include "KillSay.h" #include "UberSpam.hpp" +#include "SkinChanger.hpp" #include "Achievement.h" #include "Spam.h" #include "Noisemaker.h" diff --git a/src/hooks/PaintTraverse.cpp b/src/hooks/PaintTraverse.cpp index a775d499..91585815 100644 --- a/src/hooks/PaintTraverse.cpp +++ b/src/hooks/PaintTraverse.cpp @@ -157,6 +157,7 @@ void PaintTraverse_hook(void* _this, unsigned int vp, bool fr, bool ar) { SAFE_CALL(hacks::shared::esp::Draw()); if (TF) SAFE_CALL(hacks::tf::spyalert::Draw()); if (TF) SAFE_CALL(hacks::tf::radar::Draw()); + if (TF2) SAFE_CALL(hacks::tf2::skinchanger::PaintTraverse()); } diff --git a/src/hooks/others.cpp b/src/hooks/others.cpp index b62a18fb..84331068 100644 --- a/src/hooks/others.cpp +++ b/src/hooks/others.cpp @@ -179,6 +179,7 @@ void FrameStageNotify_hook(void* _this, int stage) { SEGV_BEGIN; if (!g_IEngine->IsInGame()) g_Settings.bInvalid = true; // TODO hack FSN hook + hacks::tf2::skinchanger::FrameStageNotify(stage); if (resolver && cathook && !g_Settings.bInvalid && stage == FRAME_NET_UPDATE_POSTDATAUPDATE_START) { for (int i = 1; i < 32 && i < HIGHEST_ENTITY; i++) { if (i == g_IEngine->GetLocalPlayer()) continue; diff --git a/src/ipc.cpp b/src/ipc.cpp index a67a75e6..ce4bce6c 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -5,13 +5,14 @@ * Author: nullifiedcat */ -#ifdef IPC_ENABLED #include "ipc.h" #include "common.h" #include "hack.h" +#ifdef IPC_ENABLED + namespace ipc { std::atomic thread_running(false);