From 6f7ebb43b1b52bcdb70092566f2cf4a671e03c04 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 5 Jun 2017 00:00:46 +0200 Subject: [PATCH] [Friends] Steam avatars --- src/Components/Modules/Friends.cpp | 66 ++++++++++++++++++++++++++ src/Components/Modules/Friends.hpp | 8 ++++ src/Components/Modules/Materials.cpp | 71 ++++++++++++++++++++++++++++ src/Components/Modules/Materials.hpp | 6 +++ src/Game/Functions.cpp | 25 ++++++++++ src/Game/Functions.hpp | 2 + 6 files changed, 178 insertions(+) diff --git a/src/Components/Modules/Friends.cpp b/src/Components/Modules/Friends.cpp index 2bd98479..0d77918c 100644 --- a/src/Components/Modules/Friends.cpp +++ b/src/Components/Modules/Friends.cpp @@ -554,6 +554,13 @@ namespace Components Command::Execute("openmenu popup_friends", true); }, HOOK_JUMP).install()->quick(); + // Avatar callback +// Steam::Proxy::RegisterCallback(333, [](void* data) +// { +// MessageBoxA(0, 0, 0, 0); +// +// }); + // Callback to update user information Steam::Proxy::RegisterCallback(336, [](void* data) { @@ -687,6 +694,64 @@ namespace Components Friends::UpdateFriends(); }); + + Command::Add("testavatar", [](Command::Params*) + { + std::lock_guard _(Friends::Mutex); + + for(auto user : Friends::FriendsList) + { + Logger::Print("Fetching %s...\n", user.name.data()); + int index = Steam::Proxy::SteamFriends->GetSmallFriendAvatar(user.userId); + + + + if (!Steam::Proxy::SteamUtils) return; + + static Game::GfxImage image = { nullptr }; + if (image.map) Game::Image_Release(&image); + static Game::Material* material = nullptr; + + unsigned int width, height; + Steam::Proxy::SteamUtils->GetImageSize(index, &width, &height); + Game::Image_Setup(&image, static_cast(width), static_cast(height), 1, 0x1000003, D3DFMT_A8R8G8B8); + + D3DLOCKED_RECT lockedRect; + image.map->LockRect(0, &lockedRect, nullptr, 0); + + unsigned char* buffer = static_cast(lockedRect.pBits); + + Steam::Proxy::SteamUtils->GetImageRGBA(index, buffer, width * height * 4); + + for (unsigned int i = 0; i < width * height * 4; i += 4) + { + unsigned char r = buffer[i + 0]; + unsigned char g = buffer[i + 1]; + unsigned char b = buffer[i + 2]; + unsigned char a = buffer[i + 3]; + + buffer[i + 0] = a; + buffer[i + 1] = r; + buffer[i + 2] = g; + buffer[i + 3] = b; + } + + image.map->UnlockRect(0); + + if (!material) + { + material = Materials::Create("avatar", &image); + + Scheduler::OnFrame([]() + { + float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + Game::CL_DrawStretchPicPhysical(10.0f, 10.0f, 100.0f, 100.0f, 0, 0, 1.0f, 1.0f, color, material); + }); + } + + break; + } + }); } Friends::~Friends() @@ -695,6 +760,7 @@ namespace Components Friends::StoreFriendsList(); + //Steam::Proxy::UnregisterCallback(333); Steam::Proxy::UnregisterCallback(336); Steam::Proxy::UnregisterCallback(304); diff --git a/src/Components/Modules/Friends.hpp b/src/Components/Modules/Friends.hpp index 5c4dfb4b..34ae5712 100644 --- a/src/Components/Modules/Friends.hpp +++ b/src/Components/Modules/Friends.hpp @@ -32,6 +32,14 @@ namespace Components }; #pragma pack(pop) + struct AvatarImageLoaded + { + SteamID m_steamID; // steamid the avatar has been loaded for + int m_iImage; // the image index of the now loaded image + int m_iWide; // width of the loaded image + int m_iTall; // height of the loaded image + }; + struct PersonaStateChange { SteamID m_ulSteamID; // steamID of the friend who changed diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index b79c0a26..07591916 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -5,6 +5,75 @@ namespace Components int Materials::ImageNameLength; Utils::Hook Materials::ImageVersionCheckHook; + std::vector Materials::MaterialTable; + + Game::Material* Materials::Create(std::string name, Game::GfxImage* image) + { + Game::Material* material = Utils::Memory::GetAllocator()->allocate(); + Game::MaterialTextureDef* texture = Utils::Memory::GetAllocator()->allocate(); + + material->textureCount = 1; + material->textureTable = texture; + + material->name = Utils::Memory::GetAllocator()->duplicateString(name); + material->sortKey = 0x22; + material->textureAtlasColumnCount = 1; + material->textureAtlasRowCount = 1; + + for(int i = 0; i < 48; ++i) + { + if(i != 4) material->stateBitsEntry[i] = -1; + } + + material->stateFlags = 3; + material->cameraRegion = 4; + material->techniqueSet = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_TECHNIQUE_SET, "2d").techniqueSet; + + material->textureTable->nameHash = Game::R_HashString("colorMap"); + material->textureTable->nameStart = 'c'; + material->textureTable->nameEnd = 'p'; + material->textureTable->sampleState = -30; + material->textureTable->info.image = image; + + Game::Material* cursor = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "ui_cursor").material; + if(cursor) + { + material->stateBitTable = cursor->stateBitTable; + material->stateBitsCount = cursor->stateBitsCount; + } + + Materials::MaterialTable.push_back(material); + + return material; + } + + void Materials::Delete(Game::Material* material) + { + if (!material) return; + + auto mat = std::find(Materials::MaterialTable.begin(), Materials::MaterialTable.end(), material); + if(mat != Materials::MaterialTable.end()) + { + Materials::MaterialTable.erase(mat); + } + + Utils::Memory::GetAllocator()->free(material->textureTable); + Utils::Memory::GetAllocator()->free(material->name); + Utils::Memory::GetAllocator()->free(material); + } + + void Materials::DeleteAll() + { + std::vector materials; + Utils::Merge(&materials, Materials::MaterialTable); + Materials::MaterialTable.clear(); + + for(auto& material : materials) + { + Materials::Delete(material); + } + } + __declspec(naked) void Materials::ImageVersionCheck() { __asm @@ -198,6 +267,8 @@ namespace Components Materials::~Materials() { + Materials::DeleteAll(); + Materials::ImageVersionCheckHook.uninstall(); } } diff --git a/src/Components/Modules/Materials.hpp b/src/Components/Modules/Materials.hpp index fe9ccd6a..0e6cd392 100644 --- a/src/Components/Modules/Materials.hpp +++ b/src/Components/Modules/Materials.hpp @@ -10,7 +10,11 @@ namespace Components static int FormatImagePath(char* buffer, size_t size, int, int, const char* image); + static Game::Material* Create(std::string name, Game::GfxImage* image); + static void Delete(Game::Material* material); + private: + static std::vector MaterialTable; static int ImageNameLength; static Utils::Hook ImageVersionCheckHook; @@ -29,5 +33,7 @@ namespace Components #endif static int MaterialComparePrint(Game::Material* m1, Game::Material* m2); + + static void DeleteAll(); }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index b3a3efbc..4d854e73 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -870,6 +870,31 @@ namespace Game return atoi(StringTable_Lookup(rankTable, 0, maxrank, 7)); } + __declspec(naked) void Image_Setup(GfxImage* /*image*/, unsigned int /*width*/, unsigned int /*height*/, unsigned int /*depth*/, unsigned int /*flags*/, int /*format*/) + { + __asm + { + pushad + xor edi, edi + + mov eax, [esp + 24h] // image + mov di, word ptr [esp + 28h] // width + push [esp + 38h] // format + push [esp + 38h] // flags + push 0 + push [esp + 3Ch] // depth + push [esp + 3Ch] // height + + mov ecx, 54AF50h + call ecx + + add esp, 14h + + popad + retn + } + } + void SortWorldSurfaces(GfxWorld* world) { DWORD* specular1 = reinterpret_cast(0x69F105C); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 68471344..cb7f79f5 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -845,6 +845,8 @@ namespace Game int CL_GetMaxXP(); + void Image_Setup(GfxImage* image, unsigned int width, unsigned int height, unsigned int depth, unsigned int flags, int format); + void SortWorldSurfaces(GfxWorld* world); void R_AddDebugLine(float* color, float* v1, float* v2); void R_AddDebugString(float *color, float *pos, float scale, const char *str);