remove bot_quota, disable it, and call BotAddCommand directly

This commit is contained in:
rtldg 2021-04-11 01:20:06 +00:00
parent b2cfc88651
commit 57e9072b19
4 changed files with 375 additions and 175 deletions

View File

@ -43,6 +43,43 @@
"linux" "78"
"mac" "78"
}
"WEAPONTYPE_UNKNOWN"
{
"windows" "19"
"linux" "19"
"mac" "19"
}
}
"Addresses"
{
"BotManager::MaintainBotQuota"
{
"signature" "BotManager::MaintainBotQuota"
}
"CCSBotManager::BotAddCommand"
{
"signature" "CCSBotManager::BotAddCommand"
}
}
"Signatures"
{
// 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"
}
// 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"
}
}
}
@ -62,6 +99,43 @@
"linux" "77"
"mac" "77"
}
"WEAPONTYPE_UNKNOWN"
{
"windows" "9"
"linux" "9"
"mac" "9"
}
}
"Addresses"
{
"BotManager::MaintainBotQuota"
{
"signature" "BotManager::MaintainBotQuota"
}
"CCSBotManager::BotAddCommand"
{
"signature" "CCSBotManager::BotAddCommand"
}
}
"Signatures"
{
// search string: "-nobots"
"BotManager::MaintainBotQuota"
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xEC\x14\xFF\x15\x2A\x2A\x2A\x2A"
"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"
}
}
}
}

View File

@ -1852,14 +1852,14 @@ native bool Shavit_IsReplayEntity(int ent);
*
* @param style Bhop style.
* @param track Timer track.
* @param delay Delay until starting.
* @param delay Delay until starting. If -1.0, then uses shavit_replay_delay
* @param client Client index.
* @param bot Bot to play on. Should be of type Replay_Central or Replay_Dynamic. -1 to create new replay bot.
* @param type ReplayBotType. Replay_Prop needs `bot` to be -1.
* @param ignorelimit Ignore cvar limit for dynamic bots.
* @return true if things work and the replay should be starting...
* @return Replay entity. 0 is returned if couldn't be created.
*/
native bool Shavit_StartReplay(int style, int track, float delay, int client, int bot, bool ignorelimit = false);
native int Shavit_StartReplay(int style, int track, float delay, int client, int bot, bool ignorelimit = false);
/**
* Starts a replay with a given set of frames.
@ -1867,16 +1867,16 @@ native bool Shavit_StartReplay(int style, int track, float delay, int client, in
*
* @param style Bhop style.
* @param track Timer track.
* @param delay Delay until starting.
* @param delay Delay until starting. If -1.0, then uses shavit_replay_delay
* @param client Client index.
* @param bot Bot to play on. Should be of type Replay_Central or Replay_Dynamic. -1 to create new replay bot.
* @param type ReplayBotType. Replay_Prop needs `bot` to be -1.
* @param ignorelimit Ignore cvar limit for dynamic bots.
* @param cache framecache_t filled with replay info and frames.
* @param size sizeof(framecache_t). Used to throw errors at you if you don't recompile plugins.
* @return true if things work and the replay should be starting...
* @return Replay entity. 0 is returned if couldn't be created.
*/
native bool Shavit_StartReplayFromFrameCache(int style, int track, float delay, int client, int bot, bool ignorelimit = false, any[] cache, int size = sizeof(framecache_t));
native int Shavit_StartReplayFromFrameCache(int style, int track, float delay, int client, int bot, bool ignorelimit = false, any[] cache, int size = sizeof(framecache_t));
/**
* Starts a replay from a replay file.
@ -1884,15 +1884,15 @@ native bool Shavit_StartReplayFromFrameCache(int style, int track, float delay,
*
* @param style Bhop style.
* @param track Timer track.
* @param delay Delay until starting.
* @param delay Delay until starting. If -1.0, then uses shavit_replay_delay
* @param client Client index.
* @param bot Bot to play on. Should be of type Replay_Central or Replay_Dynamic. -1 to create new replay bot.
* @param type ReplayBotType. Replay_Prop needs `bot` to be -1.
* @param ignorelimit Ignore cvar limit for dynamic bots.
* @param path File path to replay
* @return true if things work and the replay should be starting...
* @return Replay entity. 0 is returned if couldn't be created.
*/
native bool Shavit_StartReplayFromFile(int style, int track, float delay, int client, int bot, bool ignorelimit = false, const char[] path);
native int Shavit_StartReplayFromFile(int style, int track, float delay, int client, int bot, bool ignorelimit = false, const char[] path);
/**
* Reloads a specific replay into the replay bot cache.

View File

@ -23,6 +23,7 @@
#include <sdkhooks>
#include <convar_class>
#include <profiler>
#include <dhooks>
#undef REQUIRE_PLUGIN
#include <shavit>
@ -110,8 +111,7 @@ enum
// custom cvar settings
char gS_ForcedCvars[][][] =
{
{ "bot_quota", "{expected_bots}" },
{ "tf_bot_quota", "{expected_bots}" },
{ "bot_quota", "0" },
{ "bot_stop", "1" },
{ "bot_quota_mode", "normal" },
{ "tf_bot_quota_mode", "normal" },
@ -162,17 +162,20 @@ Handle gH_OnReplaySaved = null;
// server specific
float gF_Tickrate = 0.0;
char gS_Map[160];
int gI_ExpectedBots = 0;
// replay bot stuff
int gI_CentralBot = -1;
loopingbot_config_t gA_LoopingBotConfig[MAX_LOOPING_BOT_CONFIGS];
ArrayList gA_BotEvents = null; // shitty fifo pipe
int gI_DynamicBots = 0;
// Replay_Prop: index with starter/watcher
// Replay_ANYTHINGELSE: index with fakeclient index
bot_info_t gA_BotInfo[MAXPLAYERS+1];
bool gB_KickedShouldDecreaseQuota[MAXPLAYERS+1];
// hooks and sdkcall stuff
Handle gH_BotAddCommand = INVALID_HANDLE;
DynamicDetour gH_MaintainBotQuota = null;
int gI_WEAPONTYPE_UNKNOWN = 123123123;
int gI_LatestClient = -1;
// how do i call this
bool gB_HideNameChange = false;
@ -199,7 +202,7 @@ Convar gCV_DynamicTimeSearch = null;
Convar gCV_DynamicTimeCheap = null;
Convar gCV_DynamicTimeTick = null;
ConVar gCV_EnableDynamicTimeDifference = null;
ConVar gCV_BotQuota = null;
ConVar sv_duplicate_playernames_ok = null;
// timer settings
int gI_Styles = 0;
@ -317,10 +320,12 @@ public void OnPluginStart()
gEV_Type = GetEngineVersion();
gF_Tickrate = (1.0 / GetTickInterval());
gCV_BotQuota = FindConVar((gEV_Type != Engine_TF2)? "bot_quota":"tf_bot_quota");
gCV_BotQuota.Flags &= ~FCVAR_NOTIFY;
FindConVar("bot_stop").Flags &= ~FCVAR_CHEAT;
gA_BotEvents = new ArrayList(sizeof(bot_info_t));
sv_duplicate_playernames_ok = FindConVar("sv_duplicate_playernames_ok");
if (sv_duplicate_playernames_ok != null)
{
sv_duplicate_playernames_ok.Flags &= ~FCVAR_REPLICATED;
}
for(int i = 0; i < sizeof(gS_ForcedCvars); i++)
{
@ -328,15 +333,7 @@ public void OnPluginStart()
if(hCvar != null)
{
if(StrEqual(gS_ForcedCvars[i][1], "{expected_bots}"))
{
UpdateBotQuota(0);
}
else
{
hCvar.SetString(gS_ForcedCvars[i][1]);
}
hCvar.SetString(gS_ForcedCvars[i][1]);
hCvar.AddChangeHook(OnForcedConVarChanged);
}
}
@ -365,11 +362,11 @@ public void OnPluginStart()
Convar.AutoExecConfig();
// late load
for(int i = 1; i <= MaxClients; i++)
{
ClearBotInfo(gA_BotInfo[i]);
// late load
if(IsValidClient(i) && !IsFakeClient(i))
{
OnClientPutInServer(i);
@ -403,6 +400,82 @@ public void OnPluginStart()
// database
GetTimerSQLPrefix(gS_MySQLPrefix, 32);
gH_SQL = GetTimerDatabaseHandle();
LoadDHooks();
}
void LoadDHooks()
{
GameData gamedata = new GameData("shavit.games");
if (gamedata == null)
{
SetFailState("Failed to load shavit gamedata");
}
StartPrepSDKCall(SDKCall_Static);
if (gEV_Type == Engine_TF2)
{
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "NextBotCreatePlayerBot<CTFBot>"))
{
SetFailState("Failed to get CCSBotManager::BotAddCommand");
}
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); // const char *name
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // bool bReportFakeClient
PrepSDKCall_SetReturnInfo(SDKType_CBasePlayer, SDKPass_Pointer); // CTFBot*
if (!(gH_BotAddCommand = EndPrepSDKCall()))
{
SetFailState("Unable to prepare SDKCall for NextBotCreatePlayerBot<CTFBot>");
}
}
else
{
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "CCSBotManager::BotAddCommand"))
{
SetFailState("Failed to get CCSBotManager::BotAddCommand");
}
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // int team
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // bool isFromConsole
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // const char *profileName
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // CSWeaponType weaponType
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // BotDifficultyType difficulty
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); // bool
if (!(gH_BotAddCommand = EndPrepSDKCall()))
{
SetFailState("Unable to prepare SDKCall for CCSBotManager::BotAddCommand");
}
}
Address addr = gamedata.GetAddress("BotManager::MaintainBotQuota");
if (!addr)
{
SetFailState("Failed to get address for BotManager::MaintainBotQuota");
}
if ((gI_WEAPONTYPE_UNKNOWN = gamedata.GetOffset("WEAPONTYPE_UNKNOWN")) == -1)
{
SetFailState("Failed to get WEAPONTYPE_UNKNOWN");
}
if (!(gH_MaintainBotQuota = DHookCreateDetour(addr, CallConv_THISCALL, ReturnType_Void, ThisPointer_Address)))
{
SetFailState("Failed to create detour for BotManager::MaintainBotQuota");
}
gH_MaintainBotQuota.Enable(Hook_Pre, Detour_MaintainBotQuota);
delete gamedata;
}
// Stops bot_quota from doing anything.
MRESReturn Detour_MaintainBotQuota(int pThis)
{
return MRES_Supercede;
}
public void OnPluginEnd()
@ -416,19 +489,9 @@ void KickAllReplays()
{
if (IsValidEntity(gA_BotInfo[i].iEnt))
{
KickReplay(gA_BotInfo[i], false);
KickReplay(gA_BotInfo[i]);
}
}
while (gA_BotEvents.Length > 0)
{
bot_info_t info;
gA_BotEvents.GetArray(0, info);
gA_BotEvents.Erase(0);
ClearBotInfo(info);
}
UpdateBotQuota(0);
}
public void OnLibraryAdded(const char[] name)
@ -464,11 +527,6 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
OnMapStart();
}
void UpdateBotQuota(int quota)
{
gCV_BotQuota.IntValue = gI_ExpectedBots = ((quota < 0) ? 0 : quota);
}
public void OnForcedConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
char sName[32];
@ -478,11 +536,7 @@ public void OnForcedConVarChanged(ConVar convar, const char[] oldValue, const ch
{
if(StrEqual(sName, gS_ForcedCvars[i][0]))
{
if(StrEqual(gS_ForcedCvars[i][1], "{expected_bots}"))
{
convar.IntValue = gI_ExpectedBots;
}
else if(!StrEqual(newValue, gS_ForcedCvars[i][1]))
if(!StrEqual(newValue, gS_ForcedCvars[i][1]))
{
convar.SetString(gS_ForcedCvars[i][1]);
}
@ -547,6 +601,8 @@ public void AdminMenu_DeleteReplay(Handle topmenu, TopMenuAction action, TopMenu
void FinishReplay(bot_info_t info)
{
int starter = GetClientFromSerial(info.iStarterSerial);
if (info.iType == Replay_Dynamic || info.iType == Replay_Prop)
{
KickReplay(info);
@ -576,6 +632,11 @@ void FinishReplay(bot_info_t info)
ClearBotInfo(info);
}
if (starter > 0)
{
gA_BotInfo[starter].iEnt = -1;
}
}
void StopOrRestartBots(int style, int track, bool restart)
@ -655,14 +716,14 @@ public int Native_GetReplayBotIndex(Handle handler, int numParams)
int track = GetNativeCell(1);
int style = GetNativeCell(2);
if ((track == -1 || style == -1) && gI_CentralBot > 0)
if (track == -1 && style == -1 && gI_CentralBot > 0)
{
return gI_CentralBot;
}
for (int i = 1; i <= MaxClients; i++)
{
if (gA_BotInfo[i].iEnt >= 1)
if (IsValidEntity(gA_BotInfo[i].iEnt) && gA_BotInfo[i].iType != Replay_Prop)
{
if ((track == -1 || gA_BotInfo[i].iTrack == track) && (style == -1 || gA_BotInfo[i].iStyle == style))
{
@ -706,6 +767,14 @@ void StartReplay(bot_info_t info, int track, int style, int starter, float delay
TeleportToStart(info);
UpdateReplayClient(info.iEnt);
if (starter > 0 && info.iType != Replay_Prop)
{
gA_BotInfo[starter].iEnt = info.iEnt;
// Timer is used because the bot's name is missing and profile pic random if using RequestFrame...
// I really have no idea. Even delaying by 5 frames wasn't enough. Broken game.
CreateTimer(0.2, Timer_SpectateMyBot, GetClientSerial(info.iEnt), TIMER_FLAG_NO_MAPCHANGE);
}
}
public int Native_IsReplayEntity(Handle handler, int numParams)
@ -726,13 +795,18 @@ void SetupIfCustomFrames(bot_info_t info, framecache_t cache)
}
}
int CreateReplay(int track, int style, float delay, int client, int bot, int type, bool ignorelimit, framecache_t cache)
int CreateReplayEntity(int track, int style, float delay, int client, int bot, int type, bool ignorelimit, framecache_t cache, int loopingConfig)
{
if(cache.iFrameCount == 0)
if (client > 0 && IsValidEntity(gA_BotInfo[client].iEnt))
{
return 0;
}
if (delay == -1.0)
{
delay = gCV_ReplayDelay.FloatValue;
}
if (bot == -1)
{
if (type == Replay_Prop)
@ -750,35 +824,47 @@ int CreateReplay(int track, int style, float delay, int client, int bot, int typ
}
SetupIfCustomFrames(gA_BotInfo[client], cache);
StartReplay(gA_BotInfo[client], gI_MenuTrack[client], gI_MenuStyle[client], client, gCV_ReplayDelay.FloatValue);
StartReplay(gA_BotInfo[client], gI_MenuTrack[client], gI_MenuStyle[client], client, delay);
}
else if (type == Replay_Dynamic)
else
{
if (!ignorelimit)
if (type == Replay_Dynamic)
{
if (gI_DynamicBots >= gCV_DynamicBotLimit.IntValue)
if (!ignorelimit && gI_DynamicBots >= gCV_DynamicBotLimit.IntValue)
{
return 0;
}
++gI_DynamicBots;
}
bot_info_t info;
info.iType = Replay_Dynamic;
info.iType = type;
info.iStyle = style;
info.iTrack = track;
info.iStarterSerial = (client > 0) ? GetClientFromSerial(client) : 0;
info.iStarterSerial = (client > 0) ? GetClientSerial(client) : 0;
info.bIgnoreLimit = ignorelimit;
info.iLoopingConfig = loopingConfig;
SetupIfCustomFrames(info, cache);
QueueAddReplayBot(info);
bot = CreateReplayBot(info);
if (bot != 0)
{
if (client > 0)
{
gA_BotInfo[client].iEnt = bot;
}
if (type == Replay_Dynamic && !ignorelimit)
{
++gI_DynamicBots;
}
}
}
}
else
{
int index = GetBotInfoIndex(bot);
if (index == 0)
if (index < 1)
{
return 0;
}
@ -795,7 +881,7 @@ int CreateReplay(int track, int style, float delay, int client, int bot, int typ
StartReplay(gA_BotInfo[index], track, style, client, delay);
}
return 1;
return bot;
}
public int Native_StartReplay(Handle handler, int numParams)
@ -809,7 +895,7 @@ public int Native_StartReplay(Handle handler, int numParams)
bool ignorelimit = view_as<bool>(GetNativeCell(7));
framecache_t cache; // null cache
return CreateReplay(track, style, delay, client, bot, type, ignorelimit, cache);
return CreateReplayEntity(track, style, delay, client, bot, type, ignorelimit, cache, 0);
}
public int Native_StartReplayFromFrameCache(Handle handler, int numParams)
@ -831,7 +917,7 @@ public int Native_StartReplayFromFrameCache(Handle handler, int numParams)
framecache_t cache;
GetNativeArray(8, cache, sizeof(cache));
return CreateReplay(track, style, delay, client, bot, type, ignorelimit, cache);
return CreateReplayEntity(track, style, delay, client, bot, type, ignorelimit, cache, 0);
}
public int Native_StartReplayFromFile(Handle handler, int numParams)
@ -854,7 +940,7 @@ public int Native_StartReplayFromFile(Handle handler, int numParams)
return 0;
}
return CreateReplay(track, style, delay, client, bot, type, ignorelimit, cache);
return CreateReplayEntity(track, style, delay, client, bot, type, ignorelimit, cache, 0);
}
public int Native_ReloadReplay(Handle handler, int numParams)
@ -1371,7 +1457,8 @@ public void OnMapStart()
Call_Finish();
}
AddReplayBots();
// Timer because sometimes a few bots don't spawn
CreateTimer(0.2, Timer_AddReplayBots, 0, TIMER_FLAG_NO_MAPCHANGE);
CreateTimer(3.0, Cron, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}
@ -1403,10 +1490,72 @@ public void Shavit_OnStyleChanged(int client, int oldstyle, int newstyle, int tr
gI_TimeDifferenceStyle[client] = newstyle;
}
void QueueAddReplayBot(bot_info_t info)
int InternalCreateReplayBot()
{
gA_BotEvents.PushArray(info);
UpdateBotQuota(gI_ExpectedBots + 1);
gI_LatestClient = -1;
if (gEV_Type == Engine_TF2)
{
/*int bot =*/ SDKCall(
gH_BotAddCommand,
"replaybot", // name
true // bReportFakeClient
);
}
else
{
/*int ret =*/ SDKCall(
gH_BotAddCommand,
gCV_DefaultTeam.IntValue, // team // TEAM_TERRORIST
false, // isFromConsole
0, // profileName // unused
gI_WEAPONTYPE_UNKNOWN, // CSWeaponType // WEAPONTYPE_UNKNOWN
0 // BotDifficultyType // unused -- BOT_EASY
);
//bool success = (0xFF & ret) != 0;
}
return gI_LatestClient;
}
int CreateReplayBot(bot_info_t info)
{
int bot = InternalCreateReplayBot();
if (bot <= 0)
{
ClearBotInfo(info);
return -1;
}
gA_BotInfo[bot] = info;
gA_BotInfo[bot].iEnt = bot;
if (info.iType == Replay_Central)
{
gI_CentralBot = bot;
ClearBotInfo(gA_BotInfo[bot]);
}
else
{
StartReplay(gA_BotInfo[bot], gA_BotInfo[bot].iTrack, gA_BotInfo[bot].iStyle, GetClientFromSerial(info.iStarterSerial), gCV_ReplayDelay.FloatValue);
}
gA_BotInfo[GetClientFromSerial(info.iStarterSerial)].iEnt = bot;
if (info.iType == Replay_Looping)
{
gA_LoopingBotConfig[info.iLoopingConfig].bSpawned = true;
}
return bot;
}
Action Timer_AddReplayBots(Handle timer, any data)
{
AddReplayBots();
return Plugin_Stop;
}
void AddReplayBots()
@ -1416,12 +1565,20 @@ void AddReplayBots()
return;
}
framecache_t cache; // NULL cache
// Load central bot if enabled...
if (gCV_CentralBot.BoolValue && gI_CentralBot <= 0)
{
bot_info_t info;
info.iType = Replay_Central;
QueueAddReplayBot(info);
int bot = CreateReplayEntity(0, 0, -1.0, 0, -1, Replay_Central, false, cache, 0);
if (bot == 0)
{
LogError("Failed to create central replay bot (client count %d)", GetClientCount());
return;
}
UpdateReplayClient(bot);
}
// Load all bots from looping config...
@ -1441,12 +1598,13 @@ void AddReplayBots()
continue;
}
bot_info_t info;
info.iType = Replay_Looping;
info.iLoopingConfig = i;
info.iStyle = style;
info.iTrack = track;
QueueAddReplayBot(info);
int bot = CreateReplayEntity(track, style, -1.0, 0, -1, Replay_Looping, false, cache, i);
if (bot == 0)
{
LogError("Failed to create looping bot %d (client count %d)", i, GetClientCount());
return;
}
}
}
@ -1828,13 +1986,13 @@ void ForceObserveProp(int client)
public void OnClientPutInServer(int client)
{
gI_LatestClient = client;
if(IsClientSourceTV(client))
{
return;
}
gB_KickedShouldDecreaseQuota[client] = false;
if(!IsFakeClient(client))
{
gA_BotInfo[client].iEnt = -1;
@ -1844,42 +2002,9 @@ public void OnClientPutInServer(int client)
SDKHook(client, SDKHook_PostThink, ForceObserveProp);
// The server kicks all the bots when it's hibernating... so let's add them back in...
if (GetClientCount() <= 1 && gI_ExpectedBots <= 0)
if (GetClientCount() <= 1)
{
AddReplayBots();
}
}
else if (gA_BotEvents.Length > 0)
{
bot_info_t info;
gA_BotEvents.GetArray(0, info);
gA_BotEvents.Erase(0);
gA_BotInfo[client] = info;
gA_BotInfo[client].iEnt = client;
if (info.iType == Replay_Central)
{
gI_CentralBot = client;
ClearBotInfo(gA_BotInfo[client]);
}
else
{
StartReplay(gA_BotInfo[client], gA_BotInfo[client].iTrack, gA_BotInfo[client].iStyle, GetClientFromSerial(info.iStarterSerial), gCV_ReplayDelay.FloatValue);
}
// Used to make the bot fucking spawn.....
RequestFrame(DelayedUpdateReplayClient, GetClientSerial(client));
if (info.iType == Replay_Dynamic)
{
// TODO: Add link to bot in gA_BotInfo[starter].iEnt...
// Dead bots can't be spectated... so let's use this to spectate them when they spawn...
RequestFrame(SpectateMyDynamicBot, GetClientSerial(client));
}
else if (info.iType == Replay_Looping)
{
gA_LoopingBotConfig[info.iLoopingConfig].bSpawned = true;
CreateTimer(0.2, Timer_AddReplayBots, 0, TIMER_FLAG_NO_MAPCHANGE);
}
}
}
@ -1983,9 +2108,21 @@ void UpdateBotScoreboard(int client)
FormatStyle(gS_ReplayStrings.sUnloaded, style, central, track, sName, idle, gA_BotInfo[client].aCache, type);
}
int sv_duplicate_playernames_ok_original;
if (sv_duplicate_playernames_ok != null)
{
sv_duplicate_playernames_ok_original = sv_duplicate_playernames_ok.IntValue;
sv_duplicate_playernames_ok.IntValue = 1;
}
gB_HideNameChange = true;
SetClientName(client, sName);
if (sv_duplicate_playernames_ok != null)
{
sv_duplicate_playernames_ok.IntValue = sv_duplicate_playernames_ok_original;
}
int iScore = (iFrameCount > 0 || client == gI_CentralBot)? 2000:-2000;
if(gEV_Type == Engine_CSGO)
@ -2000,7 +2137,13 @@ void UpdateBotScoreboard(int client)
SetEntProp(client, Prop_Data, "m_iDeaths", 0);
}
void SpectateMyDynamicBot(int serial)
Action Timer_SpectateMyBot(Handle timer, any data)
{
SpectateMyBot(data);
return Plugin_Stop;
}
void SpectateMyBot(int serial)
{
int bot = GetClientFromSerial(serial);
@ -2009,14 +2152,6 @@ void SpectateMyDynamicBot(int serial)
return;
}
if (!IsPlayerAlive(bot))
{
// Uhh.... recursion lmao....
// The bot doesn't like to respawn immediately and it's really annoying
RequestFrame(SpectateMyDynamicBot, GetClientSerial(bot));
return;
}
int starter = GetClientFromSerial(gA_BotInfo[bot].iStarterSerial);
if (starter == 0)
@ -2027,11 +2162,6 @@ void SpectateMyDynamicBot(int serial)
SetEntPropEnt(starter, Prop_Send, "m_hObserverTarget", bot);
}
void DelayedUpdateReplayClient(int serial)
{
UpdateReplayClient(GetClientFromSerial(serial));
}
void RemoveAllWeapons(int client)
{
int weapon = -1, max = GetEntPropArraySize(client, Prop_Send, "m_hMyWeapons");
@ -2138,23 +2268,16 @@ public void OnClientDisconnect(int client)
{
RequestFrame(ClearFrames, client);
if (gA_BotInfo[client].iEnt >= 1) // Remove Replay_Prop's
if (IsValidEntity(gA_BotInfo[client].iEnt))
{
KickReplay(gA_BotInfo[client]);
KickReplay(gA_BotInfo[GetBotInfoIndex(gA_BotInfo[client].iEnt)]);
}
return;
}
if (gB_KickedShouldDecreaseQuota[client])
{
UpdateBotQuota(gI_ExpectedBots - 1);
return;
}
if (gA_BotInfo[client].iEnt == client)
{
UpdateBotQuota(gI_ExpectedBots - 1);
CancelReplay(gA_BotInfo[client], false);
gA_BotInfo[client].iEnt = -1;
@ -2163,11 +2286,11 @@ public void OnClientDisconnect(int client)
{
gA_LoopingBotConfig[gA_BotInfo[client].iLoopingConfig].bSpawned = false;
}
}
if (gI_CentralBot == client)
{
gI_CentralBot = -1;
}
if (gI_CentralBot == client)
{
gI_CentralBot = -1;
}
}
@ -2529,7 +2652,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
aFrame.buttons = buttons;
aFrame.flags = GetEntityFlags(client);
aFrame.mt = GetEntityMoveType(client);
//GetEntPropVector(client, Prop_Data, "m_vecVelocity", aFrame.vel); // TODO: m_vecBaseVelocity? m_vecAbsVelocity?
//GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", aFrame.vel);
gA_PlayerFrames[client].SetArray(gI_PlayerFrames[client]++, aFrame, sizeof(frame_t));
@ -2609,7 +2732,9 @@ public Action BotEvents(Event event, const char[] name, bool dontBroadcast)
return Plugin_Continue;
}
if(event.GetBool("bot"))
int client = GetClientOfUserId(event.GetInt("userid"));
if(event.GetBool("bot") || !client || IsFakeClient(client))
{
event.BroadcastDisabled = true;
return Plugin_Changed;
@ -2845,7 +2970,7 @@ public int DeleteConfirmation_Callback(Menu menu, MenuAction action, int param1,
int CreateReplayProp(int client)
{
if (gA_BotInfo[client].iEnt >= 1)
if (IsValidEntity(gA_BotInfo[client].iEnt))
{
return -1;
}
@ -2914,18 +3039,19 @@ void OpenReplayTypeMenu(int client)
char sDisplay[64];
char sInfo[8];
bool alreadyHaveBot = IsValidEntity(gA_BotInfo[client].iEnt);
FormatEx(sDisplay, sizeof(sDisplay), "%T", "Menu_Replay_Central", client);
IntToString(Replay_Central, sInfo, sizeof(sInfo));
menu.AddItem(sInfo, sDisplay, (gCV_CentralBot.BoolValue && IsValidClient(gI_CentralBot) && gA_BotInfo[gI_CentralBot].iStatus == Replay_Idle) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
menu.AddItem(sInfo, sDisplay, (gCV_CentralBot.BoolValue && IsValidClient(gI_CentralBot) && gA_BotInfo[gI_CentralBot].iStatus == Replay_Idle && !alreadyHaveBot) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
FormatEx(sDisplay, sizeof(sDisplay), "%T", "Menu_Replay_Dynamic", client);
IntToString(Replay_Dynamic, sInfo, sizeof(sInfo));
menu.AddItem(sInfo, sDisplay, (gI_DynamicBots < gCV_DynamicBotLimit.IntValue) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
menu.AddItem(sInfo, sDisplay, (gI_DynamicBots < gCV_DynamicBotLimit.IntValue && !alreadyHaveBot) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
FormatEx(sDisplay, sizeof(sDisplay), "%T", "Menu_Replay_Prop", client);
IntToString(Replay_Prop, sInfo, sizeof(sInfo));
menu.AddItem(sInfo, sDisplay, (gCV_AllowPropBots.BoolValue) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
menu.AddItem(sInfo, sDisplay, (gCV_AllowPropBots.BoolValue && !alreadyHaveBot) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
bool canstop = false;
int target = GetSpectatorTarget(client);
@ -2981,7 +3107,8 @@ public int MenuHandler_ReplayType(Menu menu, MenuAction action, int param1, int
if ((type == Replay_Central && (!gCV_CentralBot.BoolValue || !IsValidClient(gI_CentralBot) || gA_BotInfo[gI_CentralBot].iStatus != Replay_Idle))
|| (type == Replay_Dynamic && (gI_DynamicBots >= gCV_DynamicBotLimit.IntValue))
|| (type == Replay_Prop && (!gCV_AllowPropBots.BoolValue)))
|| (type == Replay_Prop && (!gCV_AllowPropBots.BoolValue))
|| IsValidEntity(gA_BotInfo[param1].iEnt))
{
return 0;
}
@ -3116,7 +3243,7 @@ public int MenuHandler_ReplayStyle(Menu menu, MenuAction action, int param1, int
int style = StringToInt(sInfo);
if(style < 0 || style >= gI_Styles || !ReplayEnabled(style) || gA_FrameCache[style][gI_MenuTrack[param1]].iFrameCount == 0)
if(style < 0 || style >= gI_Styles || !ReplayEnabled(style) || gA_FrameCache[style][gI_MenuTrack[param1]].iFrameCount == 0 || IsValidEntity(gA_BotInfo[param1].iEnt))
{
return 0;
}
@ -3126,6 +3253,8 @@ public int MenuHandler_ReplayStyle(Menu menu, MenuAction action, int param1, int
FinishReplay(gA_BotInfo[param1]);
int bot = -1;
if (type == Replay_Central)
{
if (!IsValidClient(gI_CentralBot))
@ -3139,8 +3268,7 @@ public int MenuHandler_ReplayStyle(Menu menu, MenuAction action, int param1, int
return 0;
}
StartReplay(gA_BotInfo[gI_CentralBot], gI_MenuTrack[param1], gI_MenuStyle[param1], param1, gCV_ReplayDelay.FloatValue);
SetEntPropEnt(param1, Prop_Send, "m_hObserverTarget", gI_CentralBot);
bot = gI_CentralBot;
}
else if (type == Replay_Dynamic)
{
@ -3149,15 +3277,6 @@ public int MenuHandler_ReplayStyle(Menu menu, MenuAction action, int param1, int
Shavit_PrintToChat(param1, "%T", "TooManyDynamicBots", param1);
return 0;
}
++gI_DynamicBots;
bot_info_t info;
info.iType = Replay_Dynamic;
info.iStyle = gI_MenuStyle[param1];
info.iTrack = gI_MenuTrack[param1];
info.iStarterSerial = GetClientSerial(param1);
info.bIgnoreLimit = false;
QueueAddReplayBot(info);
}
else if (type == Replay_Prop)
{
@ -3165,13 +3284,16 @@ public int MenuHandler_ReplayStyle(Menu menu, MenuAction action, int param1, int
{
return 0;
}
}
int ent = CreateReplayProp(param1);
framecache_t cache; // NULL cache
bot = CreateReplayEntity(gI_MenuTrack[param1], gI_MenuStyle[param1], gCV_ReplayDelay.FloatValue, param1, bot, type, false, cache, 0);
if (IsValidEntity(ent))
{
StartReplay(gA_BotInfo[param1], gI_MenuTrack[param1], gI_MenuStyle[param1], param1, gCV_ReplayDelay.FloatValue);
}
if (bot == 0)
{
// failed
Shavit_PrintToChat(param1, "%T", "FailedToCreateReplay", param1);
return 0;
}
}
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
@ -3304,6 +3426,7 @@ void CancelReplay(bot_info_t info, bool update = true)
if(starter != 0)
{
gF_LastInteraction[starter] = GetEngineTime();
gA_BotInfo[starter].iEnt = -1;
}
if (update)
@ -3319,7 +3442,7 @@ void CancelReplay(bot_info_t info, bool update = true)
}
}
void KickReplay(bot_info_t info, bool decreaseQuota = true)
void KickReplay(bot_info_t info)
{
if (info.iEnt <= 0)
{
@ -3331,14 +3454,9 @@ void KickReplay(bot_info_t info, bool decreaseQuota = true)
--gI_DynamicBots;
}
int starter = GetClientFromSerial(info.iStarterSerial);
CancelReplay(info, false);
if (1 <= info.iEnt <= MaxClients)
{
KickClient(info.iEnt);
gB_KickedShouldDecreaseQuota[info.iEnt] = decreaseQuota;
if (info.iType == Replay_Looping)
{
@ -3347,6 +3465,8 @@ void KickReplay(bot_info_t info, bool decreaseQuota = true)
}
else // Replay_Prop
{
int starter = GetClientFromSerial(info.iStarterSerial);
if (starter != 0)
{
// Unset target so we don't get hud errors in the single frame the prop is still alive...
@ -3356,6 +3476,8 @@ void KickReplay(bot_info_t info, bool decreaseQuota = true)
AcceptEntityInput(info.iEnt, "Kill");
}
CancelReplay(info, false);
info.iEnt = -1;
info.iType = -1;
}
@ -3550,7 +3672,7 @@ float GetClosestReplayTime(int client)
}
float clientVel[3];
GetEntPropVector(client, Prop_Data, "m_vecVelocity", clientVel); // TODO: m_vecBaseVelocity? m_vecAbsVelocity?
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", clientVel);
float fReplayPrevPos[3], fReplayClosestPos[3];
gA_FrameCache[style][track].aFrames.GetArray(iClosestFrame, fReplayClosestPos, 3);

View File

@ -90,4 +90,8 @@
{
"en" "Too many dynamic bots are playing. Can't spawn more."
}
"FailedToCreateReplay"
{
"en" "Failed to create replay"
}
}