diff --git a/addons/sourcemod/gamedata/shavit.games.txt b/addons/sourcemod/gamedata/shavit.games.txt index ac07a203..1ec87152 100644 --- a/addons/sourcemod/gamedata/shavit.games.txt +++ b/addons/sourcemod/gamedata/shavit.games.txt @@ -4,16 +4,15 @@ { "Keys" { - "IGameMovement" "GameMovement001" + "IGameMovement" "GameMovement001" } "Signatures" { "CreateInterface" { - "library" "server" - "windows" "@CreateInterface" - "linux" "@CreateInterface" + "windows" "@CreateInterface" + "linux" "@CreateInterface" } } @@ -21,14 +20,14 @@ { "OS" { - "windows" "1" - "linux" "2" + "windows" "1" + "linux" "2" } "ProcessMovement" { - "windows" "1" - "linux" "2" + "windows" "1" + "linux" "2" } } } @@ -40,9 +39,9 @@ // search string "#SFUI_Notice_SprayPaint_TooClose" to find IsAbleToApplySpray and then go to the next function to find GetPlayerMaxSpeed. Then calculate the vtable offset. "CCSPlayer::GetPlayerMaxSpeed" { - "windows" "505" - "linux" "506" - "mac" "506" + "windows" "505" + "linux" "506" + "mac" "506" } // add 1 to the css offset and hope it works "CGameRules::IsSpawnPointValid" @@ -70,32 +69,29 @@ "Signatures" { // search string: "silencer_detach" and then check the function calls above it - "CCSPlayer::DoAnimationEvent" + "Player::DoAnimationEvent" { - "library" "server" - "windows" "\x55\x8B\xEC\x56\x8B\xF1\x57\x80\xBE\x2A\x2A\x2A\x2A\x00\x74\x2A\x51" - "linux" "\x55\x89\xE5\x83\xEC\x28\x89\x5D\xF4\x8B\x5D\x08\x89\x75\xF8\x8B\x75\x0C\x89\x7D\xFC\x8B\x7D\x10\x80\xBB\x44\x23\x00\x00\x00" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\x57\x80\xBE\x2A\x2A\x2A\x2A\x00\x74\x2A\x51" + "linux" "\x55\x89\xE5\x83\xEC\x28\x89\x5D\xF4\x8B\x5D\x08\x89\x75\xF8\x8B\x75\x0C\x89\x7D\xFC\x8B\x7D\x10\x80\xBB\x44\x23\x00\x00\x00" } // search string: "-nobots" "BotManager::MaintainBotQuota" { - "library" "server" - "windows" "\x55\x8B\xEC\x83\xEC\x18\x89\x4D\x2A\xFF\x15\x2A\x2A\x2A\x2A" - "linux" "\x55\x89\xE5\x83\xEC\x78\x89\x7D\x2A\x8B\x7D\x2A\x89\x5D\x2A\x89\x75\x2A" + "windows" "\x55\x8B\xEC\x83\xEC\x18\x89\x4D\x2A\xFF\x15" + "linux" "\x55\x89\xE5\x83\xEC\x78\x89\x7D\x2A\x8B\x7D\x2A\x89\x5D\x2A\x89\x75\x2A" } // search string: "Error - no profile for '%s' exists." "CCSBotManager::BotAddCommand" { - "library" "server" - "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x53\x56\x57\x80\x78\x2A\x00" - "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x4C\x8B\x15\x2A\x2A\x2A\x2A\x8B\x7D\x2A\x8B\x75\x2A\x0F\xB6\x5D\x2A" + "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x53\x56\x57\x80\x78\x2A\x00" + "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x4C\x8B\x15\x2A\x2A\x2A\x2A\x8B\x7D\x2A\x8B\x75\x2A\x0F\xB6\x5D\x2A" } // search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher. // Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher. "PhysicsCheckForEntityUntouch" { - "windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86\xD0\x00\x00\x00" - "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2C\x8B\x5D\x08\xC7\x44\x24\x04\x01\x00\x00\x00\x89\x1C\x24" + "windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86\xD0\x00\x00\x00" + "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2C\x8B\x5D\x08\xC7\x44\x24\x04\x01\x00\x00\x00\x89\x1C\x24" } } } @@ -107,9 +103,9 @@ // https://asherkin.github.io/vtable/ "CCSPlayer::GetPlayerMaxSpeed" { - "windows" "438" - "linux" "439" - "mac" "439" + "windows" "438" + "linux" "439" + "mac" "439" } // https://asherkin.github.io/vtable/ "CGameRules::IsSpawnPointValid" @@ -136,32 +132,78 @@ "Signatures" { // search string: "ReloadEffect" to find CWeaponCSBase::SendReloadEvents and then DoAnimationEvent is probably the second to last function called there. - "CCSPlayer::DoAnimationEvent" + "Player::DoAnimationEvent" { - "library" "server" - "windows" "\x55\x8B\xEC\x83\xEC\x10\x89\x4D\xFC\x83\x7D\x08\x02" - "linux" "@_ZN9CCSPlayer16DoAnimationEventE17PlayerAnimEvent_ti" + "windows" "\x55\x8B\xEC\x83\xEC\x10\x89\x4D\xFC\x83\x7D\x08\x02" + "linux" "@_ZN9CCSPlayer16DoAnimationEventE17PlayerAnimEvent_ti" } // search string: "-nobots" "BotManager::MaintainBotQuota" { - "library" "server" - "windows" "\x55\x8B\xEC\x83\xEC\x14\xFF\x15\x2A\x2A\x2A\x2A" - "linux" "@_ZN13CCSBotManager16MaintainBotQuotaEv" + "windows" "\x55\x8B\xEC\x83\xEC\x14\xFF\x15" + "linux" "@_ZN13CCSBotManager16MaintainBotQuotaEv" } // search string: "Error - no profile for '%s' exists." "CCSBotManager::BotAddCommand" { - "library" "server" - "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x80\x78\x2A\x00\x75\x2A\x83\xB8\x2A\x2A\x2A\x2A\x00" - "linux" "@_ZN13CCSBotManager13BotAddCommandEibPKc12CSWeaponType17BotDifficultyType" + "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x80\x78\x2A\x00\x75\x2A\x83\xB8\x2A\x2A\x2A\x2A\x00" + "linux" "@_ZN13CCSBotManager13BotAddCommandEibPKc12CSWeaponType17BotDifficultyType" } // search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher. // Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher. "PhysicsCheckForEntityUntouch" { - "windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\x8B\x86\x38\x03\x00\x00" - "linux" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv" + "windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\x8B\x86\x38\x03\x00\x00" + "linux" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv" + } + } + } + + "tf" + { + "Offsets" + { + // https://asherkin.github.io/vtable/ + "CGameRules::IsSpawnPointValid" + { + "windows" "76" + "linux" "77" + "mac" "77" + } + // https://asherkin.github.io/vtable/ + "CBasePlayer::UpdateStepSound" + { + "windows" "361" + "linux" "362" + } + } + + "Signatures" + { + // search string: "Usage: setang_exact pitch yaw" to find setang_exact's handler. Then the last function call in the handler is DoAnimationEvent. + "Player::DoAnimationEvent" + { + "windows" "\x55\x8B\xEC\x51\x53\x56\x8B\x35\x2A\x2A\x2A\x2A\x8B\xD9\x8B\xCE" + "linux" "@_ZN9CTFPlayer16DoAnimationEventE17PlayerAnimEvent_ti" + } + // search string: "match" + "BotManager::MaintainBotQuota" + { + "windows" "\x55\x8B\xEC\x81\xEC\x14\x01\x00\x00\xA1" + "linux" "@_ZN13CTFBotManager16MaintainBotQuotaEv" + } + // search string: "CreatePlayerBot: Unable to create bot" + "NextBotCreatePlayerBot" + { + "windows" "\x55\x8B\xEC\x56\x57\x68\x2A\x2A\x2A\x2A\xE8" + "linux" "@_Z22NextBotCreatePlayerBotI6CTFBotEPT_PKcb" + } + // search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher. + // Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher. + "PhysicsCheckForEntityUntouch" + { + "windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\x8B\x86\x2A\x2A\x2A\x2A\xD1\xE8\xA8\x01" + "linux" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv" } } } diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index adfea374..4a9002be 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -1460,10 +1460,12 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen) void UpdateMainHUD(int client) { int target = GetSpectatorTarget(client, client); + bool bReplay = (gB_Replay && Shavit_IsReplayEntity(target)); if((gI_HUDSettings[client] & HUD_CENTER) == 0 || ((gI_HUDSettings[client] & HUD_OBSERVE) == 0 && client != target) || - (gEV_Type == Engine_TF2 && (!gB_FirstPrint[target] || GetEngineTime() - gF_ConnectTime[target] < 1.5))) // TF2 has weird handling for hint text + (!IsValidClient(target) && !bReplay) || + (gEV_Type == Engine_TF2 && IsValidClient(target) && (!gB_FirstPrint[target] || GetEngineTime() - gF_ConnectTime[target] < 1.5))) // TF2 has weird handling for hint text { return; } @@ -1472,7 +1474,6 @@ void UpdateMainHUD(int client) GetEntPropVector(target, Prop_Data, "m_vecVelocity", fSpeed); float fSpeedHUD = ((gI_HUDSettings[client] & HUD_2DVEL) == 0)? GetVectorLength(fSpeed):(SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0))); - bool bReplay = (gB_Replay && Shavit_IsReplayEntity(target)); ZoneHUD iZoneHUD = ZoneHUD_None; int iReplayStyle = 0; int iReplayTrack = 0; @@ -1747,12 +1748,18 @@ void UpdateTopLeftHUD(int client, bool wait) if((!wait || gI_Cycle % 25 == 0) && (gI_HUDSettings[client] & HUD_TOPLEFT) > 0) { int target = GetSpectatorTarget(client, client); + bool bReplay = (gB_Replay && Shavit_IsReplayEntity(target)); + + if (!bReplay && !IsValidClient(target)) + { + return; + } int track = 0; int style = 0; float fTargetPB = 0.0; - if(!(gB_Replay && Shavit_IsReplayEntity(target))) + if(!bReplay) { style = Shavit_GetBhopStyle(target); track = Shavit_GetClientTrack(target); @@ -1867,6 +1874,12 @@ void UpdateKeyHint(int client) if(target == client || (gI_HUDSettings[client] & HUD_OBSERVE) > 0) { int bReplay = gB_Replay && Shavit_IsReplayEntity(target); + + if (!bReplay && !IsValidClient(target)) + { + return; + } + int style = bReplay ? Shavit_GetReplayBotStyle(target) : Shavit_GetBhopStyle(target); if(!(0 <= style < gI_Styles)) diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index d36521c0..726022e2 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -335,53 +335,11 @@ public void OnPluginStart() CreateTimer(10.0, Timer_Cron, 0, TIMER_REPEAT); CreateTimer(0.5, Timer_PersistKZCP, 0, TIMER_REPEAT); + LoadDHooks(); + if(gEV_Type != Engine_TF2) { CreateTimer(1.0, Timer_Scoreboard, 0, TIMER_REPEAT); - - if(LibraryExists("dhooks")) - { - Handle hGameData = LoadGameConfigFile("shavit.games"); - - if(hGameData != null) - { - int iOffset = GameConfGetOffset(hGameData, "CCSPlayer::GetPlayerMaxSpeed"); - - if(iOffset != -1) - { - gH_GetPlayerMaxSpeed = DHookCreate(iOffset, HookType_Entity, ReturnType_Float, ThisPointer_CBaseEntity, CCSPlayer__GetPlayerMaxSpeed); - } - else - { - SetFailState("Couldn't get the offset for \"CCSPlayer::GetPlayerMaxSpeed\" - make sure your gamedata is updated!"); - } - - if ((iOffset = GameConfGetOffset(hGameData, "CBasePlayer::UpdateStepSound")) != -1) - { - gH_UpdateStepSound = new DynamicHook(iOffset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity); - gH_UpdateStepSound.AddParam(HookParamType_ObjectPtr); - gH_UpdateStepSound.AddParam(HookParamType_VectorPtr); - gH_UpdateStepSound.AddParam(HookParamType_VectorPtr); - } - else - { - LogError("Couldn't get the offset for \"CBasePlayer::UpdateStepSound\" - make sure your gamedata is updated!"); - } - - if ((iOffset = GameConfGetOffset(hGameData, "CGameRules::IsSpawnPointValid")) != -1) - { - gH_IsSpawnPointValid = new DynamicHook(iOffset, HookType_GameRules, ReturnType_Bool, ThisPointer_Ignore); - gH_IsSpawnPointValid.AddParam(HookParamType_CBaseEntity); - gH_IsSpawnPointValid.AddParam(HookParamType_CBaseEntity); - } - else - { - SetFailState("Couldn't get the offset for \"CGameRules::IsSpawnPointValid\" - make sure your gamedata is updated!"); - } - } - - delete hGameData; - } } // late load @@ -409,6 +367,52 @@ public void OnPluginStart() gB_Chat = LibraryExists("shavit-chat"); } +void LoadDHooks() +{ + Handle hGameData = LoadGameConfigFile("shavit.games"); + + if(hGameData == null) + { + SetFailState("Failed to load shavit gamedata"); + } + + int iOffset = GameConfGetOffset(hGameData, "CCSPlayer::GetPlayerMaxSpeed"); + + if(iOffset != -1) + { + gH_GetPlayerMaxSpeed = DHookCreate(iOffset, HookType_Entity, ReturnType_Float, ThisPointer_CBaseEntity, CCSPlayer__GetPlayerMaxSpeed); + } + else if (gEV_Type != Engine_TF2) + { + SetFailState("Couldn't get the offset for \"CCSPlayer::GetPlayerMaxSpeed\" - make sure your gamedata is updated!"); + } + + if ((iOffset = GameConfGetOffset(hGameData, "CBasePlayer::UpdateStepSound")) != -1) + { + gH_UpdateStepSound = new DynamicHook(iOffset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity); + gH_UpdateStepSound.AddParam(HookParamType_ObjectPtr); + gH_UpdateStepSound.AddParam(HookParamType_VectorPtr); + gH_UpdateStepSound.AddParam(HookParamType_VectorPtr); + } + else + { + LogError("Couldn't get the offset for \"CBasePlayer::UpdateStepSound\" - make sure your gamedata is updated!"); + } + + if ((iOffset = GameConfGetOffset(hGameData, "CGameRules::IsSpawnPointValid")) != -1) + { + gH_IsSpawnPointValid = new DynamicHook(iOffset, HookType_GameRules, ReturnType_Bool, ThisPointer_Ignore); + gH_IsSpawnPointValid.AddParam(HookParamType_CBaseEntity); + gH_IsSpawnPointValid.AddParam(HookParamType_CBaseEntity); + } + else + { + SetFailState("Couldn't get the offset for \"CGameRules::IsSpawnPointValid\" - make sure your gamedata is updated!"); + } + + delete hGameData; +} + public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) { if (sv_disable_radar != null) @@ -1233,11 +1237,6 @@ public void OnClientPutInServer(int client) SDKHook(client, SDKHook_WeaponDrop, OnWeaponDrop); SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); - if(gEV_Type == Engine_TF2) - { - SDKHook(client, SDKHook_PreThinkPost, OnPreThink); - } - if(IsFakeClient(client)) { if (gCV_BotFootsteps.BoolValue && gH_UpdateStepSound != null) @@ -1248,6 +1247,18 @@ public void OnClientPutInServer(int client) return; } + if(gEV_Type == Engine_TF2) + { + SDKHook(client, SDKHook_PreThinkPost, OnPreThink); + } + else + { + if(gH_GetPlayerMaxSpeed != null) + { + DHookEntity(gH_GetPlayerMaxSpeed, true, client); + } + } + if(!AreClientCookiesCached(client)) { gI_Style[client] = Shavit_GetBhopStyle(client); @@ -1255,11 +1266,6 @@ public void OnClientPutInServer(int client) gI_CheckpointsSettings[client] = CP_DEFAULT; } - if(gH_GetPlayerMaxSpeed != null) - { - DHookEntity(gH_GetPlayerMaxSpeed, true, client); - } - if(gA_Checkpoints[client] == null) { gA_Checkpoints[client] = new ArrayList(sizeof(cp_cache_t)); diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 43e4527d..34168c64 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -117,6 +117,11 @@ enum CSS_ANIM_JUMP } +enum +{ + TF2_ANIM_JUMP = 6 +} + enum { CSGO_ANIM_FIRE_GUN_PRIMARY, @@ -341,8 +346,15 @@ public void OnPluginStart() gEV_Type = GetEngineVersion(); gF_Tickrate = (1.0 / GetTickInterval()); - FindConVar("bot_stop").Flags &= ~FCVAR_CHEAT; + ConVar bot_stop = FindConVar("bot_stop"); + + if (bot_stop != null) + { + bot_stop.Flags &= ~FCVAR_CHEAT; + } + sv_duplicate_playernames_ok = FindConVar("sv_duplicate_playernames_ok"); + if (sv_duplicate_playernames_ok != null) { sv_duplicate_playernames_ok.Flags &= ~FCVAR_REPLICATED; @@ -475,11 +487,11 @@ void LoadDHooks() { SetFailState("Unable to prepare SDKCall for CCSBotManager::BotAddCommand"); } - } - if ((gI_WEAPONTYPE_UNKNOWN = gamedata.GetOffset("WEAPONTYPE_UNKNOWN")) == -1) - { - SetFailState("Failed to get WEAPONTYPE_UNKNOWN"); + if ((gI_WEAPONTYPE_UNKNOWN = gamedata.GetOffset("WEAPONTYPE_UNKNOWN")) == -1) + { + SetFailState("Failed to get WEAPONTYPE_UNKNOWN"); + } } if (!(gH_MaintainBotQuota = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Void, ThisPointer_Address))) @@ -494,16 +506,9 @@ void LoadDHooks() gH_MaintainBotQuota.Enable(Hook_Pre, Detour_MaintainBotQuota); - if(gB_Linux) - { - StartPrepSDKCall(SDKCall_Static); - } - else - { - StartPrepSDKCall(SDKCall_Player); - } + StartPrepSDKCall(gB_Linux ? SDKCall_Static : SDKCall_Player); - if (PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "CCSPlayer::DoAnimationEvent")) + if (PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "Player::DoAnimationEvent")) { if(gB_Linux) { @@ -1546,11 +1551,18 @@ int InternalCreateReplayBot() if (gEV_Type == Engine_TF2) { - /*int bot =*/ SDKCall( + int bot = SDKCall( gH_BotAddCommand, "replaybot", // name true // bReportFakeClient ); + + if (IsValidClient(bot)) + { + TF2_ChangeClientTeam(bot, TFTeam_Red); + TF2_SetPlayerClass(bot, TFClass_Sniper); + SetFakeClientConVar(bot, "name", "replaybot"); + } } else { @@ -1558,7 +1570,7 @@ int InternalCreateReplayBot() { /*int ret =*/ SDKCall( gH_BotAddCommand, - 0x10000, // thisptr // unused + 0x10000, // thisptr // unused (sourcemod needs > 0xFFFF though) gCV_DefaultTeam.IntValue, // team false, // isFromConsole 0, // profileName // unused @@ -2643,7 +2655,8 @@ Action ReplayOnPlayerRunCmd(bot_info_t info, int &buttons, int &impulse, float v if((g_iLastReplayFlags[info.iEnt] & FL_ONGROUND) && !(iReplayFlags & FL_ONGROUND) && gH_DoAnimationEvent != INVALID_HANDLE) { - int jumpAnim = GetEngineVersion() == Engine_CSS ? CSS_ANIM_JUMP:CSGO_ANIM_JUMP; + int jumpAnim = (gEV_Type == Engine_CSS) ? + CSS_ANIM_JUMP : ((gEV_Type == Engine_TF2) ? TF2_ANIM_JUMP : CSGO_ANIM_JUMP); if(gB_Linux) {