You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

390 lines
15 KiB
C++

12 months ago
#include <stdio.h>
#include "Skin.h"
#include "metamod_oslink.h"
#include "utils.hpp"
#include <utlstring.h>
#include <KeyValues.h>
#include "sdk/schemasystem.h"
#include "sdk/CBaseEntity.h"
#include "sdk/CGameRulesProxy.h"
#include "sdk/CBasePlayerPawn.h"
#include "sdk/CCSPlayerController.h"
#include "sdk/CCSPlayer_ItemServices.h"
#include "sdk/CSmokeGrenadeProjectile.h"
#include <map>
#ifdef _WIN32
#include <Windows.h>
#include <TlHelp32.h>
#else
#include "utils/module.h"
#endif
#include <string>
Skin g_Skin;
PLUGIN_EXPOSE(Skin, g_Skin);
IVEngineServer2* engine = nullptr;
IGameEventManager2* gameeventmanager = nullptr;
IGameResourceServiceServer* g_pGameResourceService = nullptr;
CGameEntitySystem* g_pGameEntitySystem = nullptr;
CEntitySystem* g_pEntitySystem = nullptr;
CSchemaSystem* g_pCSchemaSystem = nullptr;
CCSGameRules* g_pGameRules = nullptr;
CPlayerSpawnEvent g_PlayerSpawnEvent;
CRoundPreStartEvent g_RoundPreStartEvent;
CEntityListener g_EntityListener;
bool g_bPistolRound;
typedef struct SkinParm
{
int m_nFallbackPaintKit;
int m_nFallbackSeed;
float m_flFallbackWear;
}SkinParm;
12 months ago
#ifdef _WIN32
typedef void*(FASTCALL* SubClassChange_t)(const CCommandContext &context, const CCommand &args);
12 months ago
typedef void*(FASTCALL* EntityRemove_t)(CGameEntitySystem*, void*, void*,uint64_t);
typedef void(FASTCALL* GiveNamedItem_t)(void* itemService,const char* pchName, void* iSubType,void* pScriptItem, void* a5,void* a6);
typedef void(FASTCALL* UTIL_ClientPrintAll_t)(int msg_dest, const char* msg_name, const char* param1, const char* param2, const char* param3, const char* param4);
11 months ago
typedef void(FASTCALL* UTIL_ClientPrint_t)(CBasePlayerController *player, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4);
12 months ago
extern SubClassChange_t FnSubClassChange;
12 months ago
extern EntityRemove_t FnEntityRemove;
extern GiveNamedItem_t FnGiveNamedItem;
extern UTIL_ClientPrintAll_t FnUTIL_ClientPrintAll;
11 months ago
extern UTIL_ClientPrint_t FnUTIL_ClientPrint;
12 months ago
EntityRemove_t FnEntityRemove;
GiveNamedItem_t FnGiveNamedItem;
UTIL_ClientPrintAll_t FnUTIL_ClientPrintAll;
11 months ago
UTIL_ClientPrint_t FnUTIL_ClientPrint;
SubClassChange_t FnSubClassChange;
12 months ago
#else
void (*FnSubClassChange)(const CCommandContext &context, const CCommand &args) = nullptr;
12 months ago
void (*FnEntityRemove)(CGameEntitySystem*, void*, void*,uint64_t) = nullptr;
void (*FnGiveNamedItem)(void* itemService,const char* pchName, void* iSubType,void* pScriptItem, void* a5,void* a6) = nullptr;
void (*FnUTIL_ClientPrintAll)(int msg_dest, const char* msg_name, const char* param1, const char* param2, const char* param3, const char* param4) = nullptr;
11 months ago
void (*FnUTIL_ClientPrint)(CBasePlayerController *player, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4) = nullptr;
12 months ago
#endif
std::map<int, std::string> g_WeaponsMap;
std::map<uint64_t, int> g_PlayerKnifes;
12 months ago
std::map<uint64_t, std::map<int, SkinParm>> g_PlayerSkins;
class GameSessionConfiguration_t { };
SH_DECL_HOOK3_void(INetworkServerService, StartupServer, SH_NOATTRIB, 0, const GameSessionConfiguration_t&, ISource2WorldSession*, const char*);
SH_DECL_HOOK3_void(IServerGameDLL, GameFrame, SH_NOATTRIB, 0, bool, bool, bool);
#ifdef _WIN32
inline void* FindSignature(const char* modname,const char* sig)
{
DWORD64 hModule = (DWORD64)GetModuleHandle(modname);
if (!hModule)
{
return NULL;
}
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 mod = {sizeof(MODULEENTRY32)};
while (Module32Next(hSnap, &mod))
{
if (!strcmp(modname, mod.szModule))
{
if(!strstr(mod.szExePath,"metamod"))
break;
}
}
CloseHandle(hSnap);
byte* b_sig = (byte*)sig;
int sig_len = strlen(sig);
byte* addr = (byte*)mod.modBaseAddr;
for (int i = 0; i < mod.modBaseSize; i++)
{
int flag = 0;
for (int n = 0; n < sig_len; n++)
{
if (i + n >= mod.modBaseSize)break;
if (*(b_sig + n)=='\x3F' || *(b_sig + n) == *(addr + i+ n))
{
flag++;
}
}
if (flag == sig_len)
{
return (void*)(addr + i);
}
}
return NULL;
}
#endif
bool Skin::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool late)
{
PLUGIN_SAVEVARS();
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer2, SOURCE2ENGINETOSERVER_INTERFACE_VERSION);
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
GET_V_IFACE_CURRENT(GetServerFactory, g_pSource2Server, ISource2Server, SOURCE2SERVER_INTERFACE_VERSION);
GET_V_IFACE_CURRENT(GetEngineFactory, g_pNetworkServerService, INetworkServerService, NETWORKSERVERSERVICE_INTERFACE_VERSION);
GET_V_IFACE_CURRENT(GetEngineFactory, g_pGameResourceService, IGameResourceServiceServer, GAMERESOURCESERVICESERVER_INTERFACE_VERSION);
GET_V_IFACE_CURRENT(GetFileSystemFactory, g_pFullFileSystem, IFileSystem, FILESYSTEM_INTERFACE_VERSION);
// Get CSchemaSystem
{
HINSTANCE m_hModule = dlmount(WIN_LINUX("schemasystem.dll", "libschemasystem.so"));
g_pCSchemaSystem = reinterpret_cast<CSchemaSystem*>(reinterpret_cast<CreateInterfaceFn>(dlsym(m_hModule, "CreateInterface"))(SCHEMASYSTEM_INTERFACE_VERSION, nullptr));
dlclose(m_hModule);
}
SH_ADD_HOOK(INetworkServerService, StartupServer, g_pNetworkServerService, SH_MEMBER(this, &Skin::StartupServer), true);
SH_ADD_HOOK(IServerGameDLL, GameFrame, g_pSource2Server, SH_MEMBER(this, &Skin::GameFrame), true);
gameeventmanager = static_cast<IGameEventManager2*>(CallVFunc<IToolGameEventAPI*, 91>(g_pSource2Server));
ConVar_Register(FCVAR_GAMEDLL);
g_WeaponsMap = {{59,"weapon_knife"},{42,"weapon_knife"},{26,"weapon_bizon"},{27,"weapon_mac10"},{34,"weapon_mp9"},{19,"weapon_p90"},{24,"weapon_ump45"},{7,"weapon_ak47"},{8,"weapon_aug"},{10,"weapon_famas"},{13,"weapon_galilar"},{16,"weapon_m4a1"},{60,"weapon_m4a1_silencer"},{39,"weapon_sg556"},{9,"weapon_awp"},{11,"weapon_g3sg1"},{38,"weapon_scar20"},{40,"weapon_ssg08"},{29,"weapon_mag7"},{35,"weapon_nova"},{29,"weapon_sawedoff"},{25,"weapon_xm1014"},{14,"weapon_m249"},{9,"weapon_awp"},{28,"weapon_negev"},{1,"weapon_deagle"},{2,"weapon_elite"},{3,"weapon_fiveseven"},{4,"weapon_glock"},{32,"weapon_hkp2000"},{36,"weapon_p250"},{30,"weapon_tec9"},{61,"weapon_usp_silencer"},{63,"weapon_cz75a"},{64,"weapon_revolver"}};
12 months ago
#ifdef _WIN32
byte* vscript = (byte*)FindSignature("vscript.dll", "\xBE\x01\x3F\x3F\x3F\x2B\xD6\x74\x61\x3B\xD6");
if(vscript)
{
DWORD pOld;
VirtualProtect(vscript, 2, PAGE_EXECUTE_READWRITE, &pOld);
*(vscript + 1) = 2;
VirtualProtect(vscript, 2, pOld, &pOld);
}
#endif
return true;
}
bool Skin::Unload(char *error, size_t maxlen)
{
SH_REMOVE_HOOK(IServerGameDLL, GameFrame, g_pSource2Server, SH_MEMBER(this, &Skin::GameFrame), true);
SH_REMOVE_HOOK(INetworkServerService, StartupServer, g_pNetworkServerService, SH_MEMBER(this, &Skin::StartupServer), true);
gameeventmanager->RemoveListener(&g_PlayerSpawnEvent);
gameeventmanager->RemoveListener(&g_RoundPreStartEvent);
g_pGameEntitySystem->RemoveListenerEntity(&g_EntityListener);
ConVar_Unregister();
return true;
}
void Skin::NextFrame(std::function<void()> fn)
{
m_nextFrame.push_back(fn);
}
void Skin::StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession*, const char*)
{
#ifdef _WIN32
11 months ago
FnUTIL_ClientPrint = (UTIL_ClientPrint_t)FindSignature("server.dll", "\x48\x85\xC9\x0F\x84\x3F\x3F\x3F\x3F\x48\x8B\xC4\x48\x89\x58\x18");
12 months ago
FnUTIL_ClientPrintAll = (UTIL_ClientPrintAll_t)FindSignature("server.dll", "\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x81\xEC\x70\x01\x3F\x3F\x8B\xE9");
FnGiveNamedItem = (GiveNamedItem_t)FindSignature("server.dll", "\x48\x89\x5C\x24\x18\x48\x89\x74\x24\x20\x55\x57\x41\x54\x41\x56\x41\x57\x48\x8D\x6C\x24\xD9");
FnEntityRemove = (EntityRemove_t)FindSignature("server.dll", "\x48\x85\xD2\x0F\x3F\x3F\x3F\x3F\x3F\x57\x48\x3F\x3F\x3F\x48\x89\x3F\x3F\x3F\x48\x8B\xF9\x48\x8B");
FnSubClassChange = (SubClassChange_t)FindSignature("server.dll", "\x40\x55\x41\x57\x48\x83\xEC\x78\x83\xBA\x38\x04");
12 months ago
#else
CModule libserver(g_pSource2Server);
11 months ago
FnUTIL_ClientPrint = libserver.FindPatternSIMD("55 48 89 E5 41 57 49 89 CF 41 56 49 89 D6 41 55 41 89 F5 41 54 4C 8D A5 A0 FE FF FF").RCast< decltype(FnUTIL_ClientPrint) >();
12 months ago
FnUTIL_ClientPrintAll = libserver.FindPatternSIMD("55 48 89 E5 41 57 49 89 D7 41 56 49 89 F6 41 55 41 89 FD").RCast< decltype(FnUTIL_ClientPrintAll) >();
FnGiveNamedItem = libserver.FindPatternSIMD("55 48 89 E5 41 57 41 56 49 89 CE 41 55 49 89 F5 41 54 49 89 D4 53 48 89").RCast<decltype(FnGiveNamedItem)>();
FnEntityRemove = libserver.FindPatternSIMD("48 85 F6 74 0B 48 8B 76 10 E9 B2 FE FF FF").RCast<decltype(FnEntityRemove)>();
FnSubClassChange = libserver.FindPatternSIMD("55 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC C8 00 00 00 83 BE 38 04 00 00 01 0F 8E 47 02").RCast<decltype(FnSubClassChange)>();
12 months ago
#endif
g_pGameRules = nullptr;
static bool bDone = false;
if (!bDone)
{
g_pGameEntitySystem = *reinterpret_cast<CGameEntitySystem**>(reinterpret_cast<uintptr_t>(g_pGameResourceService) + WIN_LINUX(0x58, 0x50));
g_pEntitySystem = g_pGameEntitySystem;
g_pGameEntitySystem->AddListenerEntity(&g_EntityListener);
gameeventmanager->AddListener(&g_PlayerSpawnEvent, "player_spawn", true);
gameeventmanager->AddListener(&g_RoundPreStartEvent, "round_prestart", true);
bDone = true;
}
}
void Skin::GameFrame(bool simulating, bool bFirstTick, bool bLastTick)
{
if (!g_pGameRules)
{
CCSGameRulesProxy* pGameRulesProxy = static_cast<CCSGameRulesProxy*>(UTIL_FindEntityByClassname(nullptr, "cs_gamerules"));
if (pGameRulesProxy)
{
g_pGameRules = pGameRulesProxy->m_pGameRules();
}
}
while (!m_nextFrame.empty())
{
m_nextFrame.front()();
m_nextFrame.pop_front();
}
}
void CPlayerSpawnEvent::FireGameEvent(IGameEvent* event)
{
if (!g_pGameRules || g_pGameRules->m_bWarmupPeriod())
return;
CBasePlayerController* pPlayerController = static_cast<CBasePlayerController*>(event->GetPlayerController("userid"));
if (!pPlayerController || pPlayerController->m_steamID() == 0) // Ignore bots
return;
}
void CRoundPreStartEvent::FireGameEvent(IGameEvent* event)
{
if (g_pGameRules)
{
g_bPistolRound = g_pGameRules->m_totalRoundsPlayed() == 0 || (g_pGameRules->m_bSwitchingTeamsAtRoundReset() && g_pGameRules->m_nOvertimePlaying() == 0) || g_pGameRules->m_bGameRestart();
}
}
void CEntityListener::OnEntitySpawned(CEntityInstance* pEntity)
{
CBasePlayerWeapon* pBasePlayerWeapon = dynamic_cast<CBasePlayerWeapon*>(pEntity);
if(!pBasePlayerWeapon)return;
12 months ago
g_Skin.NextFrame([pBasePlayerWeapon = pBasePlayerWeapon]()
{
int64_t steamid = pBasePlayerWeapon->m_OriginalOwnerXuidLow();
if(!steamid)return;
int64_t weaponId = pBasePlayerWeapon->m_AttributeManager().m_Item().m_iItemDefinitionIndex();
auto weapon = g_PlayerSkins.find(steamid);
if(weapon == g_PlayerSkins.end())return;
auto skin_parm = weapon->second.find(weaponId);
if(skin_parm == weapon->second.end())return;
12 months ago
pBasePlayerWeapon->m_nFallbackPaintKit() = skin_parm->second.m_nFallbackPaintKit;
pBasePlayerWeapon->m_nFallbackSeed() = skin_parm->second.m_nFallbackSeed;
pBasePlayerWeapon->m_flFallbackWear() = skin_parm->second.m_flFallbackWear;
pBasePlayerWeapon->m_AttributeManager().m_Item().m_iItemIDHigh() = -1;
pBasePlayerWeapon->m_CBodyComponent()->m_pSceneNode()->GetSkeletonInstance()->m_modelState().m_MeshGroupMask() = 2;
if(weaponId == 59 || weaponId == 42)
{
auto knife_idx = g_PlayerKnifes.find(steamid);
if(knife_idx == g_PlayerKnifes.end())return;
char buf[64] = {0};
int index = static_cast<CEntityInstance*>(pBasePlayerWeapon)->m_pEntity->m_EHandle.GetEntryIndex();
sprintf(buf,"i_subclass_change %d %d",knife_idx->second,index);
engine->ServerCommand(buf);
}
META_CONPRINTF( "class: %s\n", static_cast<CEntityInstance*>(pBasePlayerWeapon)->m_pEntity->m_designerName.String());
12 months ago
META_CONPRINTF( "steamId: %lld itemId: %d\n", steamid, weaponId);
});
}
CON_COMMAND_F(skin, "修改皮肤", FCVAR_CLIENT_CAN_EXECUTE)
{
if(context.GetPlayerSlot() == -1)return;
CCSPlayerController* pPlayerController = (CCSPlayerController*)g_pEntitySystem->GetBaseEntity((CEntityIndex)(context.GetPlayerSlot().Get() + 1));
CCSPlayerPawnBase* pPlayerPawn = pPlayerController->m_hPlayerPawn();
if (!pPlayerPawn || pPlayerPawn->m_lifeState() != LIFE_ALIVE)
return;
12 months ago
CPlayer_WeaponServices* pWeaponServices = pPlayerPawn->m_pWeaponServices();
int64_t steamid = pPlayerController->m_steamID();
int64_t weaponId = pWeaponServices->m_hActiveWeapon()->m_AttributeManager().m_Item().m_iItemDefinitionIndex();
auto weapon_name = g_WeaponsMap.find(weaponId);
if(weapon_name == g_WeaponsMap.end())return;
11 months ago
if(args.ArgC() == 1)
{
FnUTIL_ClientPrint(pPlayerController, 3, " \x04 [SKIN] \x01访问http://skin.ymos.top/ 生成皮肤修改参数",nullptr, nullptr, nullptr, nullptr);
FnUTIL_ClientPrint(pPlayerController, 3, " \x04 [SKIN] \x01开源仓库https://github.com/yuzhouUvU/cs2_weapons_skin",nullptr, nullptr, nullptr, nullptr);
return;
}
char buf[255] = {0};
if(weaponId == 59 || weaponId == 42)
{
if(args.ArgC() != 5)
{
11 months ago
sprintf(buf, " \x04 [SKIN] \x01%s 你使用skin命令修改刀皮肤需要四个参数!",pPlayerController->m_iszPlayerName());
FnUTIL_ClientPrint(pPlayerController, 3, buf,nullptr, nullptr, nullptr, nullptr);
return;
}
g_PlayerKnifes[steamid] = atoi(args.Arg(4));
}
else
{
if(args.ArgC() != 4)
{
11 months ago
sprintf(buf, " \x04 [SKIN] \x01%s 你使用skin命令修改武器皮肤需要三个参数!",pPlayerController->m_iszPlayerName());
FnUTIL_ClientPrint(pPlayerController, 3, buf,nullptr, nullptr, nullptr, nullptr);
return;
}
}
12 months ago
g_PlayerSkins[steamid][weaponId].m_nFallbackPaintKit = atoi(args.Arg(1));
g_PlayerSkins[steamid][weaponId].m_nFallbackSeed = atoi(args.Arg(2));
g_PlayerSkins[steamid][weaponId].m_flFallbackWear = atof(args.Arg(3));
CBasePlayerWeapon* pPlayerWeapon = pWeaponServices->m_hActiveWeapon();
pWeaponServices->RemoveWeapon(pPlayerWeapon);
FnEntityRemove(g_pGameEntitySystem,pPlayerWeapon,nullptr,-1);
FnGiveNamedItem(pPlayerPawn->m_pItemServices(),weapon_name->second.c_str(),nullptr,nullptr,nullptr,nullptr);
// pPlayerWeapon->m_AttributeManager().m_Item().m_iAccountID() = 271098320;
12 months ago
//CCSPlayer_ItemServices* pItemServices = static_cast<CCSPlayer_ItemServices*>(pPlayerPawn->m_pItemServices());
//pItemServices->GiveNamedItem(weapon_name->second.c_str());
// g_pGameRules->PlayerRespawn(static_cast<CCSPlayerPawn*>(pPlayerPawn));
META_CONPRINTF( "called by %lld\n", steamid);
11 months ago
sprintf(buf, " \x04 [SKIN] \x01已修改皮肤 编号:%d 模板:%d 磨损:%f",g_PlayerSkins[steamid][weaponId].m_nFallbackPaintKit,g_PlayerSkins[steamid][weaponId].m_nFallbackSeed,g_PlayerSkins[steamid][weaponId].m_flFallbackWear);
FnUTIL_ClientPrint(pPlayerController, 3, buf,nullptr, nullptr, nullptr, nullptr);
12 months ago
}
CON_COMMAND_F(i_subclass_change, "subclass change", FCVAR_NONE)
{
FnSubClassChange(context,args);
}
12 months ago
const char* Skin::GetLicense()
{
return "GPL";
}
const char* Skin::GetVersion()
{
return "1.0.0";
}
const char* Skin::GetDate()
{
return __DATE__;
}
const char* Skin::GetLogTag()
{
return "skin";
}
const char* Skin::GetAuthor()
{
return "宇宙遨游";
}
const char* Skin::GetDescription()
{
return "武器皮肤插件";
}
const char* Skin::GetName()
{
return "武器皮肤插件";
}
const char* Skin::GetURL()
{
return "http://cs2.wssr.top";
}