diff --git a/csgo2/events.cpp b/csgo2/events.cpp index a15a1af..f95bf7e 100644 --- a/csgo2/events.cpp +++ b/csgo2/events.cpp @@ -1,6 +1,83 @@ #include "events.h" namespace events { +auto OnPlayerHurtEvent(IGameEvent* event) -> void { + /* + auto luaCall_onPlayerHurt(int userid, int attacker, int health, int armor, + const char* weapon, int dmg_health, int dmg_armor, + int hitgroup) -> void + */ + UnkGameEventStruct_t userIdNameParams{ "userid" }; + UnkGameEventStruct_t attackerNameParams{ "attacker" }; + UnkGameEventStruct_t healthNameParams{0}; + UnkGameEventStruct_t armorNameParams{0}; + UnkGameEventStruct_t weaponNameParams{0}; + UnkGameEventStruct_t dmg_healthNameParams{0}; + UnkGameEventStruct_t dmg_armorNameParams{0}; + UnkGameEventStruct_t hitgroupNameParams{0}; + + static const auto healthStr = "health"; + static const auto armorStr = "armor"; + static const auto weaponStr = "weapon"; + static const auto dmg_healthStr = "dmg_health"; + static const auto dmg_armorStr = "dmg_armor"; + static const auto hitgroupStr = "hitgroup"; + + + healthNameParams.m_Unk = Offset::FnServerHashFunction( + healthStr, sizeof healthStr, SERVER_HASH_FUCNTION_KEY); + healthNameParams.m_Key = healthStr; + + armorNameParams.m_Unk = Offset::FnServerHashFunction( + armorStr, sizeof armorStr, SERVER_HASH_FUCNTION_KEY); + armorNameParams.m_Key = armorStr; + + weaponNameParams.m_Unk = Offset::FnServerHashFunction( + weaponStr, sizeof weaponStr, SERVER_HASH_FUCNTION_KEY); + + weaponNameParams.m_Key = weaponStr; + + dmg_healthNameParams.m_Unk = Offset::FnServerHashFunction( + dmg_healthStr, sizeof dmg_healthStr, SERVER_HASH_FUCNTION_KEY); + dmg_healthNameParams.m_Key = dmg_healthStr; + + dmg_armorNameParams.m_Unk = Offset::FnServerHashFunction( + dmg_armorStr, sizeof dmg_armorStr, SERVER_HASH_FUCNTION_KEY); + dmg_armorNameParams.m_Key = dmg_armorStr; + + hitgroupNameParams.m_Unk = Offset::FnServerHashFunction( + hitgroupStr, sizeof hitgroupStr, SERVER_HASH_FUCNTION_KEY); + hitgroupNameParams.m_Key = hitgroupStr; + + const auto victimPawn = reinterpret_cast( + event->GetPlayerPawn(&userIdNameParams)); + const auto attackerPawn = reinterpret_cast( + event->GetPlayerPawn(&attackerNameParams)); + if (victimPawn == nullptr || attackerPawn == nullptr) { + return; + } + if (victimPawn->IsBasePlayerController() == false || + attackerPawn->IsBasePlayerController() == false) { + return; + } + const auto victim = victimPawn->GetPlayerController(); + const auto attacker = attackerPawn->GetPlayerController(); + if (victim == nullptr || attacker == nullptr) { + return; + } + const auto victimIndex = victim->GetRefEHandle().GetEntryIndex(); + const auto attackerIndex = attacker->GetRefEHandle().GetEntryIndex(); + + auto health = event->GetInt(&healthNameParams); + auto armor = event->GetInt(&armorNameParams); + auto weapon = event->GetString(&weaponNameParams); + auto dmg_health = event->GetInt(&dmg_healthNameParams); + auto dmg_armor = event->GetInt(&dmg_armorNameParams); + auto hitgroup = event->GetInt(&hitgroupNameParams); + ScriptCallBacks::luaCall_onPlayerHurt(victimIndex, attackerIndex, health, armor, + weapon, dmg_health, dmg_armor, + hitgroup); +} auto OnRoundEndEvent(IGameEvent* event) -> void { /* "winner" "byte" // winner team/user i diff --git a/csgo2/events.h b/csgo2/events.h index dce7912..a39ca12 100644 --- a/csgo2/events.h +++ b/csgo2/events.h @@ -13,4 +13,5 @@ auto OnPlayerDisconnect(int slot, const char* pszName, uint64_t xuid, auto OnPlayerSpawnEvent(IGameEvent* event) -> void; auto OnRoundStartEvent(IGameEvent* event) -> void; auto OnRoundEndEvent(IGameEvent* event) -> void; +auto OnPlayerHurtEvent(IGameEvent* event) -> void; } // namespace events diff --git a/csgo2/hooks.cpp b/csgo2/hooks.cpp index 42d0ccd..4300839 100644 --- a/csgo2/hooks.cpp +++ b/csgo2/hooks.cpp @@ -16,9 +16,12 @@ CCSWeaponBase_Spawn_t origin_CCSWeaponBase_Spawn = NULL; void __fastcall hook_CCSWeaponBase_Spawn(CBaseEntity* pThis, void* a2) { const char* pszClassName = pThis->m_pEntity()->m_designerName; - LOG("Weapon spawn: %s\n", pszClassName); origin_CCSWeaponBase_Spawn(pThis, a2); + if (pszClassName == nullptr) { + return; + } + LOG("Weapon spawn: %s\n", pszClassName); do { auto pWeapon = reinterpret_cast(pThis); @@ -165,6 +168,7 @@ bool __fastcall hook_FireEventServerSide(CGameEventManager* rcx, hash_32_fnv1a_const("player_spawn"); static constexpr auto round_start = hash_32_fnv1a_const("round_start"); static constexpr auto round_end = hash_32_fnv1a_const("round_end"); + static constexpr auto player_hurt = hash_32_fnv1a_const("player_hurt"); switch (hash_32_fnv1a_const(eventName)) { case player_death: @@ -179,6 +183,9 @@ bool __fastcall hook_FireEventServerSide(CGameEventManager* rcx, case round_end: events::OnRoundEndEvent(event); break; + case player_hurt: + events::OnPlayerHurtEvent(event); + break; // V社bug,这不会有用 /* case player_chat: diff --git a/csgo2/native_sdk.h b/csgo2/native_sdk.h index 2b0b812..8edae3e 100644 --- a/csgo2/native_sdk.h +++ b/csgo2/native_sdk.h @@ -152,6 +152,7 @@ class SchemaClassInfoData_t { return m_schema_parent->m_class; } + private: char pad_0x0000[0x8]; // 0x0000 @@ -206,7 +207,6 @@ class CUtlVector_NativeSdk { class CBaseEntity; - class CEntityIdentity { public: CBaseEntity* entity; // 0 @@ -332,6 +332,7 @@ class CBaseEntity : public CEntityInstance { SCHEMA_FIELD(int, m_iTeamNum) // SCHEMA_FIELD(Vector, m_vecBaseVelocity) SCHEMA_FIELD(CCollisionProperty*, m_pCollision) + SCHEMA_FIELD(Vector, m_vecBaseVelocity) auto IsBasePlayerController() -> bool; auto SpawnClientEntity() -> void; }; @@ -425,9 +426,8 @@ class CEconEntity { PSCHEMA_FIELD(CAttributeContainer, m_AttributeManager); }; -class CCSWeaponBase : public CEconEntity -{ -public: +class CCSWeaponBase : public CEconEntity { + public: DECLARE_CLASS(CCSWeaponBase) }; class CBasePlayerWeapon : public CEconEntity { @@ -461,7 +461,24 @@ class CPlayer_MovementServices { public: DECLARE_CLASS(CPlayer_MovementServices); }; +class CGlowProperty { + public: + DECLARE_SCHEMA_CLASS_INLINE(CGlowProperty) + SCHEMA_FIELD(Vector, m_fGlowColor) + SCHEMA_FIELD(int, m_iGlowType) + SCHEMA_FIELD(int, m_nGlowRange) + SCHEMA_FIELD(Color, m_glowColorOverride) + SCHEMA_FIELD(bool, m_bFlashing) + SCHEMA_FIELD(bool, m_bGlowing) +}; +class CBaseModelEntity { + public: + DECLARE_CLASS(CBaseModelEntity); + + SCHEMA_FIELD(CCollisionProperty, m_Collision) + SCHEMA_FIELD(CGlowProperty, m_Glow) +}; class CBasePlayerPawn : public CBaseEntity { public: DECLARE_CLASS(CBasePlayerPawn); diff --git a/csgo2/script_apis.cpp b/csgo2/script_apis.cpp index 0d37601..6d72e4d 100644 --- a/csgo2/script_apis.cpp +++ b/csgo2/script_apis.cpp @@ -149,7 +149,7 @@ auto luaApi_GetPlayerHealth(lua_State* luaVm) -> int { const auto playerIndex = lua_tointeger(luaVm, 1); int playerHealth = 0; ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { - auto playerPawn = playerController->m_hPawn().Get(); + auto playerPawn = playerController->m_hPawn().Get(); playerHealth = playerPawn->m_iHealth(); }); lua_pop(luaVm, 1); @@ -509,6 +509,31 @@ auto luaApi_MakePlayerWeaponDrop(lua_State* luaVm) -> int { lua_pushboolean(luaVm, isSuccess); return 1; } +auto luaApi_MakePlayerCurrentWeaponDrop(lua_State* luaVm) -> int { + // param: playerIndex:int, itemClass:string + const auto playerIndex = lua_tointeger(luaVm, 1); + auto isSuccess = false; + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + do { + const auto weaponServices = playerController->m_hPawn() + .Get() + ->m_pWeaponServices(); + if (weaponServices == nullptr) { + break; + } + const auto activeWeapon = + weaponServices->m_hActiveWeapon().Get(); + if (activeWeapon == nullptr) { + return; + } + weaponServices->RemoveWeapon(activeWeapon); + isSuccess = true; + } while (false); + }); + lua_pop(luaVm, 1); + lua_pushboolean(luaVm, isSuccess); + return 1; +} auto luaApi_RemovePlayerWeapon(lua_State* luaVm) -> int { // param: playerIndex:int, itemClass:string const auto playerIndex = lua_tointeger(luaVm, 1); @@ -577,6 +602,116 @@ auto luaApi_SentToAllPlayerChat(lua_State* luaVm) -> int { lua_pop(luaVm, 2); return 0; } +auto luaApi_ChangePlayeriAccount(lua_State* luaVm) -> int { + // param: playerIndex:int, x:float, y:float, z:float + const auto playerIndex = lua_tointeger(luaVm, 1); + const auto number = lua_tonumber(luaVm, 2); + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + playerController->m_pInGameMoneyServices()->m_iAccount(number); + }); + lua_pop(luaVm, 2); + return 0; +} +auto luaApi_GetPlayeriAccount(lua_State* luaVm) -> int { + // param: playerIndex:int, x:float, y:float, z:float + const auto playerIndex = lua_tointeger(luaVm, 1); + auto number = 0; + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + number = playerController->m_pInGameMoneyServices()->m_iAccount(); + }); + lua_pop(luaVm, 1); + lua_pushinteger(luaVm, number); + return 1; +} +auto luaApi_GetPlayerVecBaseVelocity(lua_State* luaVm) -> int { + // param: playerIndex:int, x:float, y:float, z:float + const auto playerIndex = lua_tointeger(luaVm, 1); + Vector number; + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + number = playerController->m_hPawn() + .Get() + ->m_vecBaseVelocity(); + }); + lua_pop(luaVm, 1); + lua_pushnumber(luaVm, number.x); + lua_pushnumber(luaVm, number.y); + lua_pushnumber(luaVm, number.z); + return 3; +} +auto luaApi_ChangePlayerVecBaseVelocity(lua_State* luaVm) -> int { + // param: playerIndex:int, x:float, y:float, z:float + const auto playerIndex = lua_tointeger(luaVm, 1); + const auto x = lua_tonumber(luaVm, 2); + const auto y = lua_tonumber(luaVm, 3); + const auto z = lua_tonumber(luaVm, 4); + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + playerController->m_hPawn().Get()->m_vecBaseVelocity( + Vector(x, y, z)); + }); + lua_pop(luaVm, 4); + return 0; +} + +auto luaApi_SetPlayerGlowColor(lua_State* luaVm) -> int { + // param: playerIndex:int, r:float, g:float, b:float, a:float + const auto playerIndex = lua_tointeger(luaVm, 1); + const auto r = lua_tonumber(luaVm, 2); + const auto g = lua_tonumber(luaVm, 3); + const auto b = lua_tonumber(luaVm, 4); + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + playerController->m_hPawn() + .Get() + ->m_Glow() + .m_fGlowColor(Vector(r, g, b)); + playerController->m_hPawn() + .Get() + ->m_Glow() + .m_glowColorOverride(Color(r, g, b, 230)); + }); + lua_pop(luaVm, 4); + return 0; +} +auto luaApi_SetPlayerGlowEnable(lua_State* luaVm) -> int { + // param: playerIndex:int, isEnable:int + const auto playerIndex = lua_tointeger(luaVm, 1); + const auto isEnable = lua_toboolean(luaVm, 2); + ExcutePlayerAction(playerIndex, [&](CCSPlayerController* playerController) { + playerController->m_hPawn() + .Get() + ->m_Glow() + .m_bGlowing(isEnable); + playerController->m_hPawn() + .Get() + ->m_Glow() + .m_iGlowType(3); + }); + lua_pop(luaVm, 2); + return 0; +} +auto luaApi_GetAllPlayerIndex(lua_State* luaVm) -> int { + // param: playerIndex:int, style:int + lua_newtable(luaVm); + CGameEntitySystem* EntitySystem = global::EntitySystem; + do { + if (EntitySystem == nullptr) { + break; + } + int index = 1; // Lua tables start at index 1 + for (size_t i = 0; i < global::MaxPlayers; i++) { + auto player = EntitySystem->GetBaseEntity(i); + + if (player == nullptr) { + break; + } + if (player->IsBasePlayerController() == false) { + break; + } + lua_pushinteger(luaVm, player->GetRefEHandle().GetEntryIndex()); + lua_rawseti(luaVm, -2, index++); + } + } while (false); + return 1; +} auto initFunciton(lua_State* luaVm) -> void { lua_register(luaVm, "ListenToGameEvent", luaApi_ListenToGameEvent); lua_register(luaVm, "luaApi_SetPlayerCurrentWeaponAmmo", @@ -602,9 +737,22 @@ auto initFunciton(lua_State* luaVm) -> void { lua_register(luaVm, "luaApi_RemovePlayerWeapon", luaApi_RemovePlayerWeapon); lua_register(luaVm, "luaApi_MakePlayerWeaponDrop", luaApi_MakePlayerWeaponDrop); + lua_register(luaVm, "luaApi_MakePlayerCurrentWeaponDrop", + luaApi_MakePlayerCurrentWeaponDrop); lua_register(luaVm, "luaApi_SendToPlayerChat", luaApi_SendToPlayerChat); lua_register(luaVm, "luaApi_SentToAllPlayerChat", luaApi_SentToAllPlayerChat); + lua_register(luaVm, "luaApi_ChangePlayerVecBaseVelocity", + luaApi_ChangePlayerVecBaseVelocity); + lua_register(luaVm, "luaApi_GetPlayerVecBaseVelocity", + luaApi_GetPlayerVecBaseVelocity); + lua_register(luaVm, "luaApi_ChangePlayeriAccount", + luaApi_ChangePlayeriAccount); + lua_register(luaVm, "luaApi_GetPlayeriAccount", luaApi_GetPlayeriAccount); + lua_register(luaVm, "luaApi_SetPlayerGlowEnable", + luaApi_SetPlayerGlowEnable); + lua_register(luaVm, "luaApi_SetPlayerGlowColor", luaApi_SetPlayerGlowColor); + lua_register(luaVm, "luaApi_GetAllPlayerIndex", luaApi_GetAllPlayerIndex); luabridge::getGlobalNamespace(luaVm) .beginClass<_luaApi_WeaponInfo>("WeaponInfo") diff --git a/csgo2/script_callbacks.cpp b/csgo2/script_callbacks.cpp index af3f14d..6448273 100644 --- a/csgo2/script_callbacks.cpp +++ b/csgo2/script_callbacks.cpp @@ -13,7 +13,7 @@ std::unordered_map callbackNameWithEnumMap{ {hash_32_fnv1a_const("player_spawn"), _CallbackNames::kOnPlayerSpawn}, {hash_32_fnv1a_const("round_start"), _CallbackNames::kOnRoundStart}, {hash_32_fnv1a_const("round_end"), _CallbackNames::kOnRoundEnd}, - + {hash_32_fnv1a_const("player_hurt"), _CallbackNames::kOnPlayerHurt}, }; auto CallBackNameToEnum(const char* name) -> _CallbackNames { if (name == nullptr) { @@ -181,4 +181,28 @@ auto luaCall_onRoundEnd(int winnerTeam, int reason, const char* message) } }); } +auto luaCall_onPlayerHurt(int userid, int attacker, int health, int armor, + const char* weapon, int dmg_health, int dmg_armor, + int hitgroup) -> void { + ExcuteCallbackInAllLuaVm(_CallbackNames::kOnPlayerHurt, + [&](lua_State* luaVm, int refIndex) -> void { + lua_rawgeti(luaVm, LUA_REGISTRYINDEX, + refIndex); + if (lua_isfunction(luaVm, -1)) { + lua_pushinteger(luaVm, userid); + lua_pushinteger(luaVm, attacker); + lua_pushinteger(luaVm, health); + lua_pushinteger(luaVm, armor); + lua_pushstring(luaVm, weapon); + lua_pushinteger(luaVm, dmg_health); + lua_pushinteger(luaVm, dmg_armor); + lua_pushinteger(luaVm, hitgroup); + if (lua_pcall(luaVm, 8, 0, 0) != LUA_OK) { + LOG("Error calling Lua callback: %s\n", + lua_tostring(luaVm, -1)); + lua_pop(luaVm, 1); + } + } + }); +} } // namespace ScriptCallBacks diff --git a/csgo2/script_callbacks.h b/csgo2/script_callbacks.h index 518afa8..c3e3ba1 100644 --- a/csgo2/script_callbacks.h +++ b/csgo2/script_callbacks.h @@ -10,7 +10,8 @@ enum class _CallbackNames { kOnPlayerSpeak, kOnPlayerSpawn, kOnRoundStart, - kOnRoundEnd + kOnRoundEnd, + kOnPlayerHurt }; extern std::unordered_map> callbackList; @@ -29,4 +30,7 @@ auto luaCall_onPlayerSpawn(int player) -> void; auto luaCall_onRoundStart(int timeLimit) -> void; auto luaCall_onRoundEnd(int winnerTeam, int reason, const char* message) -> void; +auto luaCall_onPlayerHurt(int userid, int attacker, int health, int armor, + const char* weapon, int dmg_health, int dmg_armor, + int hitgroup) -> void; } // namespace ScriptCallBacks diff --git a/csgo2/script_engine.cpp b/csgo2/script_engine.cpp index 8174ad5..f9c2526 100644 --- a/csgo2/script_engine.cpp +++ b/csgo2/script_engine.cpp @@ -47,7 +47,7 @@ auto initLuaScripts() -> void { ScriptApis::initFunciton(L); pluginEnvs[dirName] = L; - if (dirPath.starts_with("disable_")) { + if (dirPath.find("disable_") != std::string::npos) { continue; } std::string file = dirPath + "\\main.lua";