ARTICLE AD BOX
I tried to create an InventoryChanger based on the Berserker. Everything works, but the skin texture is crooked when mapped, as if the weapon has an incorrect UV mesh. This problem occurs with absolutely all skins.
Parsing all skins from GitHub
void ParseSkinsFromWeb() { const std::string url = "https://raw.githubusercontent.com/ByMykel/CSGO-API/refs/heads/main/public/api/en/skins.json"; std::string jsonData = DownloadString(url); if (jsonData.empty()) return; try { auto parsed = json::parse(jsonData, nullptr, false); if (parsed.is_discarded()) return; std::map<uint16_t, c_dumped_item> items_map; for (auto& skin_entry : parsed) { if (!skin_entry.contains("weapon") || skin_entry["weapon"].is_null()) continue; auto& w_node = skin_entry["weapon"]; uint16_t w_id = 0; if (w_node.contains("weapon_id")) { auto& val = w_node["weapon_id"]; if (val.is_number()) w_id = val.get<uint16_t>(); else if (val.is_string()) w_id = (uint16_t)std::stoi(val.get<std::string>()); } if (w_id == 0) continue; if (items_map.find(w_id) == items_map.end()) { c_dumped_item new_item; new_item.m_def_index = w_id; new_item.m_name = w_node.value("name", "Unknown Weapon"); items_map[w_id] = new_item; } c_dumped_skins skin; if (skin_entry.contains("paint_index") && !skin_entry["paint_index"].is_null()) { auto& pi_val = skin_entry["paint_index"]; if (pi_val.is_string()) skin.m_id = std::stoi(pi_val.get<std::string>()); else if (pi_val.is_number()) skin.m_id = pi_val.get<int>(); } if (skin_entry.contains("pattern") && !skin_entry["pattern"].is_null()) { skin.m_name = skin_entry["pattern"].value("name", "Standard"); } else { skin.m_name = "Standard"; } if (skin_entry.contains("rarity") && !skin_entry["rarity"].is_null()) { std::string r_id = skin_entry["rarity"].value("id", ""); if (r_id == "rarity_common_weapon") skin.m_rarity = 1; else if (r_id == "rarity_uncommon_weapon") skin.m_rarity = 2; else if (r_id == "rarity_rare_weapon") skin.m_rarity = 3; else if (r_id == "rarity_mythical_weapon") skin.m_rarity = 4; else if (r_id == "rarity_legendary_weapon") skin.m_rarity = 5; else if (r_id == "rarity_ancient_weapon") skin.m_rarity = 6; else if (r_id.find("ancient") != std::string::npos) skin.m_rarity = 6; else if (r_id == "rarity_contraband_weapon") skin.m_rarity = 7; } items_map[w_id].m_dumped_skins.push_back(skin); } m_dumped_items.clear(); for (auto const& [id, item] : items_map) { m_dumped_items.push_back(item); } } catch (const std::exception& e) { printf("er: %s\n", e.what()); } }The skin add function (used in the UI)
void AddSkinToInventory(S::c_dumped_item* item, S::c_dumped_skins* skin) { if (!item || !skin) return; CCSPlayerInventory* pInventory = CCSPlayerInventory::GetInstance(); if (!pInventory) return; CEconItem* pItem = CEconItem::CreateInstance(); if (!pItem) return; auto highestIDs = pInventory->GetHighestIDs(); pItem->m_ulID = highestIDs.first + 1; pItem->m_unInventory = 1 << 30; pItem->m_unAccountID = uint32_t(pInventory->GetOwner().m_id); pItem->m_unDefIndex = item->m_def_index; pItem->m_nQuality = 4; pItem->m_nRarity = skin->m_rarity; pItem->SetPaintKit(skin->m_id); pItem->SetPaintSeed(1); pItem->SetPaintWear(0.001f); pInventory->AddEconItem(pItem); auto pInvManager = CCSInventoryManager::GetInstance(); if (pInvManager) { pInvManager->EquipItemInLoadout(2, item->m_def_index, pItem->m_ulID); pInvManager->EquipItemInLoadout(3, item->m_def_index, pItem->m_ulID); } S::AddEconItemToList(pItem, (float)skin->m_id, 1.f, 0.001f, false); }Mesh creating, using paintseed, paintkit, etc.
void ApplyWeaponSkins(C_CSPlayerPawn* pLocalPawn, CCSPlayerInventory* pInventory, C_CS2HudModelWeapon* pHudModelWeapon) { if (!pLocalPawn || (uintptr_t)pLocalPawn < 0x1000000) return; if (!pInventory || (uintptr_t)pInventory < 0x1000000) return; C_CSWeaponBase* pWeapon = pLocalPawn->GetActiveWeaponPlayer(); if (!pWeapon || (uintptr_t)pWeapon < 0x1000000) return; CGameSceneNode* pWeaponSceneNode = pWeapon->GetGameSceneNode(); if (!pWeaponSceneNode) return; C_AttributeContainer* pAttributeContainer = &pWeapon->m_AttributeManager(); C_EconItemView* pWeaponItemView = &pAttributeContainer->m_Item(); if (!pWeaponItemView) return; C_EconItemDefinition* pWeaponDefinition = pWeaponItemView->get_static_data(); if (!pWeaponDefinition || pWeaponDefinition->is_knife(false)) return; const uint64_t steamID = pInventory->GetOwner().m_id; const auto nLoadoutSlot = pWeaponDefinition->GetLoadoutSlot(); C_EconItemView* pInLoadout = pInventory->GetItemInLoadout(pWeapon->m_iOriginalTeamNumber(), nLoadoutSlot); if (!pInLoadout || pInLoadout->m_iItemID() == 0) return; const uint64_t oldItemID = pWeaponItemView->m_iItemID(); if (oldItemID != pInLoadout->m_iItemID()) { pWeaponItemView->m_iItemID() = pInLoadout->m_iItemID(); pWeaponItemView->m_iItemIDHigh() = pInLoadout->m_iItemIDHigh(); pWeaponItemView->m_iItemIDLow() = pInLoadout->m_iItemIDLow(); pWeaponItemView->m_iAccountID() = uint32_t(steamID); pWeaponItemView->m_bDisallowSOCm() = false; pWeaponItemView->m_bRestoreCustomMaterialAfterPrecache() = true; pWeapon->UpdateComposite(1); pWeapon->UpdateCompositeSec(1); S::clear_hud(pWeaponItemView); } }
