#pragma semicolon 1 #pragma newdecls required #define PLUGIN_AUTHOR "jenz" #define PLUGIN_VERSION "1.0" #define generic_length 256 #include #include #include #include #include #include #include #define MAX_AUTISM_BOTS 4 int g_BotIndex[MAXPLAYERS + 1]; // 0 = not an autism bot, 1-4 = autism bot index int ports[7] = {48470, 48471, 48472, 48473, 48474, 48479, 48480}; //last three indexes are ports its sending udp from in plugin int server_ports[2] = {27015, 27035}; //server ports: ze, ze2 bool chat_cooldown = false; //socket for bot communication Handle global_socket = null; ConVar g_cvHostPort; public Plugin myinfo = { name = "autism bot connection", author = PLUGIN_AUTHOR, description = "connection state management for the autism bots", version = PLUGIN_VERSION, url = "" }; public void OnPluginStart() { g_cvHostPort = FindConVar("hostport"); //talking RegConsoleCmd("sm_autism", cmd_talk, "talking to the bot through java application"); RegConsoleCmd("sm_botrtv", cmd_botrtv, "making bots rtv"); HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy); //UDP connection connect_socket(); chat_cooldown = false; // map downloads go to the first port only, once per cycle CreateTimer(60.0, Timer_MapDownload, _, TIMER_REPEAT); // per-bot connect checks, staggered 5 seconds apart for (int index = 1; index <= MAX_AUTISM_BOTS; index++) { CreateTimer(float(index - 1) * 5.0 + 0.1, Timer_StartConnectCheck, index); } // team joining / killing bots when no human is left alive CreateTimer(2.0, Timer_CheckTeam, _, TIMER_REPEAT); // late load for (int i = 1; i <= MaxClients; i++) { if (IsValidClient(i) && IsClientAuthorized(i)) { OnClientPostAdminCheck(i); } } } // --------------------------------------------------------------------------- // bot identification // --------------------------------------------------------------------------- int GetBotClientForIndex(int index) { for (int i = 1; i <= MaxClients; i++) { if (IsValidClient(i) && g_BotIndex[i] == index) { return i; } } return -1; } public void OnClientPutInServer(int client) { g_BotIndex[client] = 0; } public void OnClientPostAdminCheck(int client) { g_BotIndex[client] = 0; if (IsFakeClient(client)) { return; } int index = GetClientAutismBotIndex(client); if (index < 1 || index > MAX_AUTISM_BOTS) { return; } g_BotIndex[client] = index; //checks if ze or ze2 char msg[generic_length]; if (g_cvHostPort.IntValue == server_ports[0]) { Format(msg, sizeof(msg), "autismo connected to ze"); } else if (g_cvHostPort.IntValue == server_ports[1]) { Format(msg, sizeof(msg), "autismo connected to ze2"); } else { return; } send_socket_msg(msg, strlen(msg), ports[index - 1]); } public void OnClientDisconnect(int client) { g_BotIndex[client] = 0; } // --------------------------------------------------------------------------- // team joining // --------------------------------------------------------------------------- public Action Timer_CheckTeam(Handle timer, any data) { for (int client = 1; client <= MaxClients; client++) { if (!IsValidClient(client) || g_BotIndex[client] == 0) { continue; } if (GetClientTeam(client) <= CS_TEAM_SPECTATOR) { ChangeClientTeam(client, CS_TEAM_T); CreateTimer(1.0, zspawn, GetClientSerial(client)); } } // no real human alive on CT anymore -> kill the bots so they dont hold up the round bool found_valid_ct = false; for (int client = 1; client <= MaxClients; client++) { if (!IsValidClient(client)) continue; if (g_BotIndex[client] == 0 && GetClientTeam(client) > CS_TEAM_T && IsPlayerAlive(client)) { found_valid_ct = true; break; } } if (!found_valid_ct) { for (int client = 1; client <= MaxClients; client++) { if (!IsValidClient(client)) continue; if (g_BotIndex[client] != 0 && IsPlayerAlive(client)) { ForcePlayerSuicide(client); } } } return Plugin_Continue; } public Action zspawn(Handle hTimer, int Serial) { int client; if ((client = GetClientFromSerial(Serial)) == 0) { return Plugin_Handled; } if (IsValidClient(client)) { FakeClientCommandEx(client, "joinclass"); FakeClientCommandEx(client, "say /zspawn"); } return Plugin_Handled; } // --------------------------------------------------------------------------- // chat / rtv // --------------------------------------------------------------------------- public void Event_RoundStart(Handle event, const char[] name, bool dontBroadcast) { chat_cooldown = false; } public void cmd_talk_help(int port, int client, char[] info) { char msg[generic_length * 5]; chat_cooldown = true; char magic_code[16]; Format(magic_code, sizeof(magic_code), autism_bot_code); //included with unloze.secrets simply. Format(msg, sizeof(msg), "clientmessage:%N %s %s", client, magic_code, info); send_socket_msg(msg, strlen(msg), port); CreateTimer(2.0, bot_chat_cooldown); } public Action cmd_talk(int client, int args) { char info[generic_length]; GetCmdArgString(info, sizeof(info)); if (strlen(info) == 0) { PrintToChat(client, "Add a message to the command if autism bot is ingame and running on discord"); return Plugin_Handled; } // kept from the original plugin: only the bot accounts themselves can use sm_autism if (g_BotIndex[client] == 0) { return Plugin_Handled; } if (chat_cooldown) { PrintToChat(client, "spamming bot too much, applying cooldown"); return Plugin_Handled; } bool bot_found = false; for (int i = 1; i <= MaxClients; i++) { if (IsValidClient(i) && g_BotIndex[i] != 0) { cmd_talk_help(ports[g_BotIndex[i] - 1], client, info); bot_found = true; } } if (!bot_found) { PrintToChat(client, "bot not connected to server"); } return Plugin_Handled; } public Action bot_chat_cooldown(Handle timer, any data) { chat_cooldown = false; return Plugin_Continue; } public Action cmd_botrtv(int client, int args) { if (CheckCommandAccess(client, "sm_kick", ADMFLAG_KICK) || CheckCommandAccess(client, "sm_reserved", ADMFLAG_RESERVATION)) { for (int i = 1; i <= MaxClients; i++) { if (IsValidClient(i) && g_BotIndex[i] != 0) { FakeClientCommandEx(i, "say rtv"); } } } return Plugin_Handled; } // --------------------------------------------------------------------------- // connection management // --------------------------------------------------------------------------- public void OnMapVoteEnd(const char[] map) { if (StrEqual(map, "##extend##") || StrEqual(map, "##dontchange##")) { return; } char msg[generic_length]; Format(msg, sizeof(msg), "download map:%s", map); send_socket_msg(msg, strlen(msg), ports[0]); } public Action Timer_MapDownload(Handle timer, any data) { char map[64]; char msg[generic_length]; if (GetNextMap(map, sizeof(map))) { Format(msg, sizeof(msg), "download map:%s", map); send_socket_msg(msg, strlen(msg), ports[0]); } GetCurrentMap(map, sizeof(map)); Format(msg, sizeof(msg), "download map:%s", map); send_socket_msg(msg, strlen(msg), ports[0]); return Plugin_Continue; } public Action Timer_StartConnectCheck(Handle timer, int index) { CreateTimer(60.0, Timer_ConnectCheck, index, TIMER_REPEAT); return Plugin_Stop; } //this is designed for being ran from several css servers public Action Timer_ConnectCheck(Handle timer, int index) { char msg[generic_length]; int client_count = GetClientCount(false); bool connected = GetBotClientForIndex(index) != -1; int port = ports[index - 1]; if (g_cvHostPort.IntValue == server_ports[0]) { int max_allowed_players = 55; if (client_count > max_allowed_players) { Format(msg, sizeof(msg), "connect to ze2"); send_socket_msg(msg, strlen(msg), port); } else if (client_count < max_allowed_players - 5 && !connected) { Format(msg, sizeof(msg), "connect to ze"); send_socket_msg(msg, strlen(msg), port); } } else if (!connected) { //in case the bot is not connected to ze2 anymore make sure that is_bot_connected_to_ze2 is set to false again Format(msg, sizeof(msg), "not connected to ze2"); send_socket_msg(msg, strlen(msg), port); } return Plugin_Continue; } // --------------------------------------------------------------------------- // socket // --------------------------------------------------------------------------- public void send_socket_msg(char[] query_msg, int len, int port) { if (global_socket != null && SocketIsConnected(global_socket)) { SocketSendTo(global_socket, query_msg, len, "127.0.0.1", port); //udp } } stock void connect_socket() { if (global_socket == null || !SocketIsConnected(global_socket)) { int target_port = ports[4]; //default ze if (g_cvHostPort.IntValue == server_ports[1]) { //ze2 target_port = ports[5]; } global_socket = SocketCreate(SOCKET_UDP, OnSocketError); SocketSetOption(global_socket, SocketReuseAddr, 1); SocketBind(global_socket, "127.0.0.0", target_port); SocketConnect(global_socket, OnSocketConnected, OnSocketReceive, OnSocketDisconnected, "127.0.0.1", target_port); } } public void OnSocketError(Handle socket, const int errorType, const int errorNum, any args) { CloseHandle(socket); if (socket == global_socket) { global_socket = null; // otherwise connect_socket would query a closed handle } LogError("[autism bot] Socket error: %d (errno %d)", errorType, errorNum); CreateTimer(10.0, TimerConnect); } public void OnSocketConnected(Handle socket, int arg) { } public void OnSocketReceive(Handle socket, char receiveData[3500], int dataSize, int hFile) { } public void OnSocketDisconnected(Handle socket, int arg) { CreateTimer(10.0, TimerConnect); } public Action TimerConnect(Handle timer, any arg) { connect_socket(); return Plugin_Stop; } stock bool IsValidClient(int client) { return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); }