diff --git a/csgo2/csgo2.vcxproj.filters b/csgo2/csgo2.vcxproj.filters index d4b9b37..8b61b51 100644 --- a/csgo2/csgo2.vcxproj.filters +++ b/csgo2/csgo2.vcxproj.filters @@ -386,9 +386,6 @@ 源文件\script_engine - - 头文件 - 源文件\native_sdk @@ -503,6 +500,9 @@ 源文件\game_time_system + + 源文件 + diff --git a/csgo2/dllmain.cpp b/csgo2/dllmain.cpp index b5b10b3..167b86b 100644 --- a/csgo2/dllmain.cpp +++ b/csgo2/dllmain.cpp @@ -16,19 +16,25 @@ auto WatchExitThread(void *ctx) -> void { unload(); } auto init(void* ctx) -> bool { + AllocConsole(); SetConsoleTitleA("huoji debug console"); freopen_s(reinterpret_cast stdout, "CONOUT$", "w", stdout); CreateThread(NULL, 0, reinterpret_cast(WatchExitThread), NULL, 0, NULL); + uint64_t serverHandle{}; + uint64_t localizeHandle{}; - while (Offset::Module_tier0 == 0) + while (Offset::Module_tier0 == 0 || serverHandle == 0 || localizeHandle == 0) { if (global::Exit) { return false; } Offset::Module_tier0 = reinterpret_cast(GetModuleHandleA("tier0")); + serverHandle = reinterpret_cast(GetModuleHandleA("server.dll")); + localizeHandle = reinterpret_cast(GetModuleHandleA("localize.dll")); + Sleep(200); } if (Offset::Init() == false) { @@ -40,6 +46,10 @@ auto init(void* ctx) -> bool { isSuccess = hooks::init(); if (isSuccess) { LOG("plugin install success !\n"); + while (Offset::InitOffsetSuccess == false) + { + Sleep(200); + } ScriptEngine::Init(); } return isSuccess; diff --git a/csgo2/hooks.cpp b/csgo2/hooks.cpp index 6a1d0b5..ab96989 100644 --- a/csgo2/hooks.cpp +++ b/csgo2/hooks.cpp @@ -36,6 +36,7 @@ void __fastcall hook_GameFrame(void* rcx, bool simulating, bool bFirstTick, } GameTimer::ExcuteTimers(); + GameTickRunTime::ExcuteTickFunctions(); return origin_GameFrame(rcx, simulating, bFirstTick, bLastTick); } void __fastcall hook_StartServer(void* rcx, diff --git a/csgo2/native_sdk.h b/csgo2/native_sdk.h index 3f495bd..969534f 100644 --- a/csgo2/native_sdk.h +++ b/csgo2/native_sdk.h @@ -459,6 +459,9 @@ class CCSPlayerPawn : public CCSPlayerPawnBase { DECLARE_CLASS(CCSPlayerPawn); SCHEMA_FIELD(const char*, m_szLastPlaceName) auto GetPlayerController() -> CCSPlayerController*; + auto ForceRespawnPlayer() { + return CALL_VIRTUAL(void, 324, this); + } }; class CGameEntitySystem; @@ -491,4 +494,7 @@ class CCSGameRules { public: DECLARE_CLASS(CCSGameRules) SCHEMA_FIELD(bool, m_bForceTeamChangeSilent) + auto PlayerRespawn(CCSPlayerPawn* PlayerPawn) { + return CALL_VIRTUAL(void, 110, this, PlayerPawn); + } }; diff --git a/csgo2/offset.cpp b/csgo2/offset.cpp index b6d2b00..401bb0b 100644 --- a/csgo2/offset.cpp +++ b/csgo2/offset.cpp @@ -11,8 +11,10 @@ uint64_t MaxPlayerNumsPtr; HashFunction_t FnServerHashFunction; StateChanged_t FnStateChanged; NetworkStateChanged_t FnNetworkStateChanged; -//CreateGameRuleInterFace_t FnCreateCCSGameRulesInterFace; +RespawnPlayer_t FnRespawnPlayer; +//CreateGameRuleInterFace_t FnCreateCCSGameRulesInterFace; +bool InitOffsetSuccess = false; namespace InterFaces { CSchemaSystem* SchemaSystem; IGameEventManager2* GameEventManager; @@ -25,7 +27,24 @@ CLocalize* ILocalize; INetworkServerService* INetworkServerServiceInteFace; CCSGameRules* CCSGameRulesInterFace; }; // namespace InterFaces +auto SafeDelayInit(void* ctx) -> void { + // ҪϷúʼ + InterFaces::CCSGameRulesInterFace = + reinterpret_cast(Memory::read(CCSGameRulesInterFacePtr)); + while (InterFaces::CCSGameRulesInterFace == 0) + { + InterFaces::CCSGameRulesInterFace = + reinterpret_cast(Memory::read(CCSGameRulesInterFacePtr)); + Sleep(100); + } + InitOffsetSuccess = true; + LOG("[huoji]InterFaces::CCSGameRulesInterFace : %llx \n", InterFaces::CCSGameRulesInterFace); + LOG("[huoji]InterFaces::CCSGameRulesInterFace->respawnPlayer : %llx \n", ((void**)InterFaces::CCSGameRulesInterFace)[110]); + + LOG("m_bForceTeamChangeSilent: %d \n", InterFaces::CCSGameRulesInterFace->m_bForceTeamChangeSilent()); + +} auto Init() -> bool { CModule server("server.dll"); CModule schemasystem("schemasystem.dll"); @@ -46,8 +65,10 @@ auto Init() -> bool { .ToAbsolute(3, 0) .Get(CGameEventManagerPtr); server.FindPattern(pattern_CreateCCSGameRulesInterFacePtr) - .ToAbsolute(10, 0) + .ToAbsolute(3, 0) .Get(CCSGameRulesInterFacePtr); + server.FindPattern(pattern_FnRespawnPlayer) + .Get(FnRespawnPlayer); server.FindPattern(pattern_fnHost_SayPtr).Get(Host_SayPtr); server.FindPattern(pattern_ServerHashFunctionPtr).Get(FnServerHashFunction); @@ -78,8 +99,7 @@ auto Init() -> bool { } InterFaces::CGameEventManger = reinterpret_cast(CGameEventManagerPtr); - InterFaces::CCSGameRulesInterFace = - reinterpret_cast(CCSGameRulesInterFacePtr + (8 * 2)); + // global::MaxPlayers = *(int*)((char*)MaxPlayerNumsPtr + 2); // client.FindPattern(pattern_FireEventServerSide).Get(FireEventServerSidePtr); global::MaxPlayers = 64; @@ -104,12 +124,11 @@ auto Init() -> bool { InterFaces::IVEngineServer); LOG("[huoji]InterFaces::ISource2ServerInterFace : %llx \n", InterFaces::ISource2ServerInterFace); - LOG("[huoji]InterFaces::CCSGameRulesInterFace : %llx \n", InterFaces::CCSGameRulesInterFace); - - //LOG("m_bForceTeamChangeSilent: %d \n", InterFaces::CCSGameRulesInterFace->m_bForceTeamChangeSilent()); LOG("init offset success !\n"); - + CreateThread(NULL, 0, + reinterpret_cast(SafeDelayInit), + NULL, 0, NULL); // LOG("FnServerHashFunction: %llx \n", FnServerHashFunction("here", // sizeof("here") - 1, 0x31415926)); return FnServerHashFunction && Host_SayPtr && InterFaces::IVEngineServer && diff --git a/csgo2/offset.h b/csgo2/offset.h index f50f325..b1a87e2 100644 --- a/csgo2/offset.h +++ b/csgo2/offset.h @@ -2,6 +2,7 @@ #include "head.h" #define SERVER_HASH_FUCNTION_KEY 0x31415926 class CEntityInstance; +class CCSPlayerPawn; typedef uint64_t(__fastcall* HashFunction_t)(const char*, unsigned int, unsigned int); typedef void(__fastcall* StateChanged_t)(void* networkTransmitComponent, @@ -10,6 +11,8 @@ typedef void(__fastcall* StateChanged_t)(void* networkTransmitComponent, typedef void(__fastcall* NetworkStateChanged_t)(uintptr_t chainEntity, uintptr_t offset, uintptr_t a3); typedef void*(__fastcall* CreateGameRuleInterFace_t)(); +typedef bool(__fastcall* RespawnPlayer_t)(CCSPlayerPawn* player); + class CSchemaSystem; class CGameResourceService; class CLocalize; @@ -55,9 +58,8 @@ static const auto pattern_ServerHashFunctionPtr = THE_GAME_SIG( static const auto pattern_MaxPlayerNumsPtr = THE_GAME_SIG("41 3B 87 ?? ?? ?? ?? 0F 8E ?? ?? ?? ?? 8B 0D ?? ?? ?? ??"); static const auto pattern_CreateCCSGameRulesInterFacePtr = THE_GAME_SIG( - "40 53 48 ?? ?? ?? B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 D2 41 ?? ?? ?? ?? ?? " - "48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 85 DB"); - + "48 ?? ?? ?? ?? ?? ?? 48 8B 01 FF ?? ?? ?? ?? ?? 48 8D ?? ?? ?? E8 ?? ?? ?? ?? 4C 8D ?? ?? ?? 49 8B ?? ?? 49 8B ?? ?? 49 8B ?? ?? 49 8B E3 41 5F 41 5E 5F C3"); +static const auto pattern_FnRespawnPlayer = THE_GAME_SIG("48 89 ?? ?? ?? 57 48 ?? ?? ?? 48 8D ?? ?? ?? 48 8B F9 E8 ?? ?? ?? ?? 83 ?? ?? 74 ?? 48 ?? ?? ?? ?? ?? ?? 48 8B CF 48 8B 10 48 8B ?? ?? ?? ?? ?? 48 8D ?? ?? ?? E8 ?? ?? ?? ?? 48 ?? ?? ?? ?? ?? ??"); extern uint64_t GameResourceServicePtr; extern uint64_t FireEventServerSidePtr; extern uint64_t Module_tier0; @@ -66,6 +68,7 @@ extern uint64_t MaxPlayerNumsPtr; extern HashFunction_t FnServerHashFunction; extern StateChanged_t FnStateChanged; extern NetworkStateChanged_t FnNetworkStateChanged; - +extern RespawnPlayer_t FnRespawnPlayer; +extern bool InitOffsetSuccess; auto Init() -> bool; }; // namespace Offset diff --git a/csgo2/script_apis.cpp b/csgo2/script_apis.cpp index f1bac3f..e91a4d5 100644 --- a/csgo2/script_apis.cpp +++ b/csgo2/script_apis.cpp @@ -12,8 +12,18 @@ struct _luaApi_WeaponInfo { int weaponType; }; namespace ScriptApis { +auto RunTickCallBack(_GameTickRunTime* timer) -> void { + LOG("excute tick function: %d %d \n", timer->m_iLuaCallBackFn, + timer->m_iParamIndex); + lua_rawgeti(timer->m_luaVm, LUA_REGISTRYINDEX, timer->m_iLuaCallBackFn); + lua_rawgeti(timer->m_luaVm, LUA_REGISTRYINDEX, timer->m_iParamIndex); + lua_pcall(timer->m_luaVm, 1, 0, 0); + luaL_unref(timer->m_luaVm, LUA_REGISTRYINDEX, timer->m_iLuaCallBackFn); + luaL_unref(timer->m_luaVm, LUA_REGISTRYINDEX, timer->m_iParamIndex); +} auto TimerCallBack(_GameTimer* timer) -> void { - LOG("excute timer: %d %d m_bRepeat: %d\n", timer->m_iLuaCallBackFn, timer->m_iParamIndex, timer->m_bRepeat); + LOG("excute timer: %d %d m_bRepeat: %d\n", timer->m_iLuaCallBackFn, + timer->m_iParamIndex, timer->m_bRepeat); lua_rawgeti(timer->m_luaVm, LUA_REGISTRYINDEX, timer->m_iLuaCallBackFn); lua_rawgeti(timer->m_luaVm, LUA_REGISTRYINDEX, timer->m_iParamIndex); lua_pcall(timer->m_luaVm, 1, 0, 0); @@ -109,8 +119,9 @@ auto luaApi_RespawnPlayer(lua_State* luaVm) -> int { } auto playerController = reinterpret_cast(player); auto playerPawn = playerController->m_hPawn().Get(); - - playerPawn->m_bRespawning(false); + LOG("respawn player: %llx \n", playerPawn); + Offset::FnRespawnPlayer(playerPawn); + //playerPawn->ForceRespawnPlayer(); } while (false); lua_pop(luaVm, 1); return 0; @@ -269,26 +280,57 @@ auto luaApi_GetPlayerCurrentWeaponInfo(lua_State* luaVm) -> _luaApi_WeaponInfo { } while (false); return info; } +auto luaApi_CreateTickRunFunction(lua_State* luaVm) -> int { + // params:lua_table, callback:function + if (!lua_istable(luaVm, 1)) { + luaL_error(luaVm, "Parameter 'params' must be a table"); + return 0; + } + lua_pushvalue(luaVm, 1); // Duplicate the table for luaL_ref + const auto params = luaL_ref(luaVm, LUA_REGISTRYINDEX); + + if (!lua_isfunction(luaVm, 2)) { + luaL_error(luaVm, "Parameter 'callback' must be a function"); + return 0; + } + lua_pushvalue(luaVm, 2); // Duplicate the function for luaL_ref + const auto callback = luaL_ref(luaVm, LUA_REGISTRYINDEX); + GameTickRunTime::AddTickFunction(new _GameTickRunTime{ + .m_luaVm = luaVm, + .m_iParamIndex = params, + .m_iLuaCallBackFn = callback, + }); + return 0; +} auto luaApi_CreateTimer(lua_State* luaVm) -> int { - // param: time:float, callback:function, params:lua_table - const auto time = lua_tonumber(luaVm, 1); + // param: time:float,repeat:bool,preservermapchange:bool,params:lua_table, + // callback:function + const auto time = luaL_checknumber(luaVm, 1); const auto repeat = lua_toboolean(luaVm, 2); const auto preserveMapChange = lua_toboolean(luaVm, 3); - auto timerHandle = 0; - do { - const auto params = lua_gettable(luaVm, 4); - const auto callback = luaL_ref(luaVm, LUA_REGISTRYINDEX); - LOG("luaApi_CreateTimer: params: %d callback: %d \n", params, callback); - timerHandle = GameTimer::AddTimer(new _GameTimer{ - .m_flTime = (float)time, - .m_bRepeat = (bool)repeat, - .m_bPreserveMapChange = (bool)preserveMapChange, - .m_luaVm = luaVm, - .m_iParamIndex = params, - .m_iLuaCallBackFn = callback - }); - } while (false); - lua_pop(luaVm, 5); + + if (!lua_istable(luaVm, 4)) { + luaL_error(luaVm, "Parameter 'params' must be a table"); + return 0; + } + lua_pushvalue(luaVm, 4); // Duplicate the table for luaL_ref + const auto params = luaL_ref(luaVm, LUA_REGISTRYINDEX); + + if (!lua_isfunction(luaVm, 5)) { + luaL_error(luaVm, "Parameter 'callback' must be a function"); + return 0; + } + lua_pushvalue(luaVm, 5); // Duplicate the function for luaL_ref + const auto callback = luaL_ref(luaVm, LUA_REGISTRYINDEX); + + auto timerHandle = GameTimer::AddTimer( + new _GameTimer{.m_flTime = (float)time, + .m_bRepeat = (bool)repeat, + .m_bPreserveMapChange = (bool)preserveMapChange, + .m_luaVm = luaVm, + .m_iParamIndex = params, + .m_iLuaCallBackFn = callback}); + lua_pushinteger(luaVm, timerHandle); return 1; } @@ -359,7 +401,7 @@ auto luaApi_SetPlayerTeam(lua_State* luaVm) -> int { break; } auto playerController = reinterpret_cast(player); - playerController->m_iTeamNum() = team; + playerController->m_iTeamNum(team); isSuccess = true; } while (false); lua_pop(luaVm, 2); @@ -401,6 +443,8 @@ auto initFunciton(lua_State* luaVm) -> void { luaApi_SetPlayerArmorValue); lua_register(luaVm, "luaApi_RespawnPlayer", luaApi_RespawnPlayer); lua_register(luaVm, "luaApi_CreateTimer", luaApi_CreateTimer); + lua_register(luaVm, "luaApi_CreateTickRunFunction", + luaApi_CreateTickRunFunction); lua_register(luaVm, "luaApi_CheckPlayerIsAlive", luaApi_CheckPlayerIsAlive); lua_register(luaVm, "luaApi_GetPlayerTeam", luaApi_GetPlayerTeam); lua_register(luaVm, "luaApi_SetPlayerTeam", luaApi_SetPlayerTeam); diff --git a/csgo2/timer.cpp b/csgo2/timer.cpp index 7bc0d9f..c709ff2 100644 --- a/csgo2/timer.cpp +++ b/csgo2/timer.cpp @@ -1,7 +1,8 @@ #include "timer.h" namespace ScriptApis { - extern auto TimerCallBack(_GameTimer* timer) -> void; -}; +extern auto TimerCallBack(_GameTimer* timer) -> void; +extern auto RunTickCallBack(_GameTickRunTime* timer) -> void; +}; // namespace ScriptApis namespace GameTimer { std::shared_mutex mutex_timerList; std::vector<_GameTimer*> timerList; @@ -27,7 +28,8 @@ auto ExcuteTimers() -> void { if ((*it)->m_flLastExecute == -1) { (*it)->m_flLastExecute = global::m_flUniversalTime; } - if ((*it)->m_flLastExecute + (*it)->m_flTime <= global::m_flUniversalTime) { + if ((*it)->m_flLastExecute + (*it)->m_flTime <= + global::m_flUniversalTime) { ScriptApis::TimerCallBack(*it); if ((*it)->m_bRepeat) { (*it)->m_flLastExecute = global::m_flUniversalTime; @@ -41,3 +43,26 @@ auto ExcuteTimers() -> void { } } }; // namespace GameTimer +namespace GameTickRunTime { +std::shared_mutex mutex_tickRunList; +std::vector<_GameTickRunTime*> tickRunList; +auto AddTickFunction(_GameTickRunTime* timer) -> void { + std::unique_lock lock(mutex_tickRunList); + tickRunList.push_back(timer); +}; +auto CleanUpTickFunctions() -> void { + std::unique_lock lock(mutex_tickRunList); + for (auto it = tickRunList.begin(); it != tickRunList.end();) { + delete (*it); + it = tickRunList.erase(it); + } +}; +auto ExcuteTickFunctions() -> void { + std::shared_lock lock(mutex_tickRunList); + for (auto it = tickRunList.begin(); it != tickRunList.end();) { + ScriptApis::RunTickCallBack(*it); + delete (*it); + it = tickRunList.erase(it); + } +} +}; // namespace GameTickRunTime diff --git a/csgo2/timer.h b/csgo2/timer.h index a5b79e6..2cf4889 100644 --- a/csgo2/timer.h +++ b/csgo2/timer.h @@ -1,18 +1,29 @@ #pragma once #include "head.h" class _GameTimer { -public: + public: float m_flTime; float m_flLastExecute = -1; bool m_bRepeat; bool m_bPreserveMapChange; - lua_State* m_luaVm; + lua_State* m_luaVm; + int m_iParamIndex; + int m_iLuaCallBackFn; +}; +class _GameTickRunTime { + public: + lua_State* m_luaVm; int m_iParamIndex; int m_iLuaCallBackFn; - }; namespace GameTimer { auto AddTimer(_GameTimer* timer) -> int; auto CleanUpTimers() -> void; auto ExcuteTimers() -> void; }; // namespace GameTimer + +namespace GameTickRunTime { +auto AddTickFunction(_GameTickRunTime* timer) -> void; +auto CleanUpTickFunctions() -> void; +auto ExcuteTickFunctions() -> void; +}; // namespace GameTickRunTime