#pragma semicolon 1 #include #include #include public Plugin:myinfo = { name = "autoexec", author = "Icewind", description = "Automatically execute the right config for a map", version = "0.5", url = "https://spire.tf" }; new StringMap:mapPrefixMap; new StringMap:mapOverwriteMap; new StringMap:mapTypeMap; new StringMap:gameModeMap; new StringMap:configOverwriteMap; bool inAutoExec = false; // size 4 so we can use team indexes bool warned[4] = {false, false, false, false}; bool initialized = false; new ConVar:CvarLeague = null; new ConVar:CvarMode = null; new ConVar:CvarAutoset = null; new ConVar:CvarWhitelist = null; public OnPluginStart() { mapPrefixMap = new StringMap(); mapOverwriteMap = new StringMap(); mapTypeMap = new StringMap(); gameModeMap = new StringMap(); configOverwriteMap = new StringMap(); CvarLeague = CreateConVar("sm_autoexec_league", "ugc", "league to execute the configs for (ugc or etf2l)", FCVAR_PROTECTED); CvarLeague.AddChangeHook(PersistLeague); CvarMode = CreateConVar("sm_autoexec_mode", "9v9", "game mode to execute the config for (9v9, 6v6 or 4v4)", FCVAR_PROTECTED); CvarMode.AddChangeHook(PersistGameMode); CvarAutoset = CreateConVar("sm_autoexec_autoset", "true", "try to set league and mode when a config is manually loaded (true or false)", FCVAR_PROTECTED); CvarWhitelist = FindConVar("mp_tournament_whitelist"); RegServerCmd("sm_autoexec", AutoExec, "Execute the config for the current map and select league and game mode"); RegServerCmd("sm_getexec", GetExec, "Get the name of the config for a specific map"); RegServerCmd("exec", HandleExecAction); mapTypeMap.SetString("5cp", "standard"); mapPrefixMap.SetString("pl_", "stopwatch"); mapPrefixMap.SetString("cp_", "5cp"); mapPrefixMap.SetString("koth_", "koth"); mapPrefixMap.SetString("ctf_", "ctf"); configOverwriteMap.SetString("ultiduo_", "etf2l_ultiduo"); configOverwriteMap.SetString("bball_", "etf2l_bball"); configOverwriteMap.SetString("ctf_bball", "etf2l_bball"); mapOverwriteMap.SetString("cp_steel", "stopwatch"); mapOverwriteMap.SetString("cp_gravelpit", "stopwatch"); mapOverwriteMap.SetString("cp_hadal", "stopwatch"); mapOverwriteMap.SetString("cp_alloy", "stopwatch"); gameModeMap.SetString("9v9", "hl"); gameModeMap.SetString("6v6", "6v"); HookEvent("tournament_stateupdate", OnReadyUp, EventHookMode_Post); } public OnMapStart() { CreateTimer(3.0, RestoreCfg); } public RestoreCfg() { RestoreGameMode(); RestoreLeague(); ExecMapCfg(); initialized = true; } public ExecMapCfg() { decl String:config[128]; decl String:map[128]; GetCurrentMap(map, sizeof(map)); GetConfig(map, config); ExecCFG(config); } public Action:HandleExecAction(args) { new String:cfg[128]; GetCmdArg(1, cfg, sizeof(cfg)); decl String:autoset[8]; GetConVarString(CvarAutoset, autoset, sizeof(autoset)); warned[2] = false; warned[3] = false; if (strncmp("true", autoset, sizeof(autoset)) != 0 || inAutoExec) { return Plugin_Continue; } if (StrContains(cfg, "etf2l_") == 0) { PrintToChatAll("Setting league to etf2l"); SetConVarString(CvarLeague, "etf2l"); } if (StrContains(cfg, "ugc_") == 0) { PrintToChatAll("Setting league to ugc"); SetConVarString(CvarLeague, "ugc"); } if ((StrContains(cfg, "9v9_") > 0) || (StrContains(cfg, "hl_") > 0)) { PrintToChatAll("Setting game mode to 9v9"); SetGameMode("9v9"); } if (StrContains(cfg, "6v6_") > 0) { PrintToChatAll("Setting game mode to 6v6"); SetGameMode("6v6"); } if (StrContains(cfg, "6v_") > 0) { PrintToChatAll("Setting game mode to 6v6"); SetGameMode("6v6"); } if (StrContains(cfg, "4v4_") > 0) { PrintToChatAll("Setting game mode to 4v4"); SetGameMode("4v4"); } if (StrContains(cfg, "ultiduo") > 0) { PrintToChatAll("Setting game mode to 2v2"); SetGameMode("2v2"); } return Plugin_Continue; } public Action:GetExec(args) { new String:map[128]; GetCmdArg(1, map, sizeof(map)); decl String:config[128]; GetConfig(map, config); PrintToChatAll("Config: %s", config); return Plugin_Handled; } public Action:AutoExec(args) { decl String:config[128]; decl String:map[128]; GetCurrentMap(map, sizeof(map)); GetConfig(map, config); ExecCFG(config); return Plugin_Handled; } public PrefixSearch(StringMap:map, String:query[128], String:result[128]) { new StringMapSnapshot:keys = map.Snapshot(); decl String:key[16]; new length = keys.Length; bool found = false; for (new i = 0; i < length; i++) { keys.GetKey(i, key, sizeof(key)); if (strncmp(key, query, strlen(key)) == 0) { found = true; map.GetString(key, result, sizeof(result)); break; } } CloseHandle(keys); return found; } public GetConfig(String:map[128], String:config[128]) { decl String:mapType[128]; decl String:league[8]; decl String:gamemode[8]; if (PrefixSearch(configOverwriteMap, map, config)) { return; } GetLeague(league); GetLeagueMapType(map, mapType, league); GetGameMode(gamemode, league); Format(config, sizeof(config), "%s_%s_%s", league, gamemode, mapType); } public GetLeague(String:league[8]) { GetConVarString(CvarLeague, league, sizeof(league)); } public GetGameMode(String:leagueGamemode[8], String:league[8]) { decl String:gamemode[8]; GetConVarString(CvarMode, gamemode, sizeof(gamemode)); if (strncmp("ugc", league, strlen(league)) == 0) { if (gameModeMap.GetString(gamemode, leagueGamemode, sizeof(leagueGamemode))) { return; } } leagueGamemode = gamemode; } public void SetGameMode(String:mode[8]) { SetConVarString(CvarMode, mode); } public void PersistGameMode(ConVar convar, const char[] oldValue, const char[] newValue) { if (!initialized) { return; } File file = OpenFile("autoexec_gamemode", "w"); file.WriteString(newValue, -1); file.Close(); } public void RestoreGameMode() { decl String:mode[8]; File file = OpenFile("autoexec_gamemode", "r"); if (file) { file.ReadString(mode, 8, -1); file.Close(); SetConVarString(CvarMode, mode); } } public void PersistLeague(ConVar convar, const char[] oldValue, const char[] newValue) { if (!initialized) { return; } File file = OpenFile("autoexec_league", "w"); file.WriteString(newValue, -1); file.Close(); } public void RestoreLeague() { decl String:league[8]; File file = OpenFile("autoexec_league", "r"); if (file) { file.ReadString(league, 8, -1); file.Close(); SetConVarString(CvarLeague, league); } } public GetLeagueMapType(String:map[128], String:leagueMapType[128], String:league[8]) { decl String:mapType[128]; GetMapType(map, mapType); if (strncmp("ugc", league, strlen(league)) == 0) { if (mapTypeMap.GetString(mapType, leagueMapType, sizeof(leagueMapType))) { return; } } leagueMapType = mapType; } public GetMapType(String:map[128], String:mapType[128]) { if (PrefixSearch(mapOverwriteMap, map, mapType)) { return; } if (!PrefixSearch(mapPrefixMap, map, mapType)) { mapType = "5cp"; //fallback } return; } public ExecCFG(String:cfg[128]) { decl String:command[256]; Format(command, sizeof(command), "exec %s", cfg); // dont trigger autoset inAutoExec = true; ServerCommand(command, sizeof(command)); CreateTimer(1.0, clearInAutoExec); // give the config time to load before clearing } public Action clearInAutoExec(Handle timer) { inAutoExec = false; return Plugin_Continue; } public void OnReadyUp(Event event, const String:name[], bool:dontBroadcast) { bool redReady = IsReady(2); bool blueReady = IsReady(3); CheckWhitelist(); if (redReady) { CheckPlayerCount(2); } if (blueReady) { CheckPlayerCount(3); } } public void CheckPlayerCount(int team) { int playerCount = GetTeamClientCount(team); int otherPlayerCount = GetTeamClientCount(OtherTeam(team)); decl String:gameMode[8]; GetConVarString(CvarMode, gameMode, sizeof(gameMode)); int expected = ExpectedPlayerCount(gameMode); if (playerCount != expected) { decl String:expectedMode[8]; decl String:expectedModeOther[8]; ExpectedGameMode(playerCount, expectedMode); ExpectedGameMode(otherPlayerCount, expectedModeOther); bool gotExpectedMode = !(strncmp("unknown", expectedMode, sizeof(expectedMode)) == 0); if (gotExpectedMode && strncmp(expectedMode, expectedModeOther, strlen(expectedMode)) == 0) { PrintToChatAll("Switching config to %s", expectedMode); SetGameMode(expectedMode); ExecMapCfg(); CreateTimer(0.5, ReadyTeamTimer, team); return; } } if (expected != 0 && !warned[team]) { if (playerCount != expected) { warned[team] = true; PrintToChatAll("Warning, config is set to %s but you readied up with %d players", gameMode, playerCount); UnReadyTeam(team); } else { warned[team] = true; } } } public bool IsReady(int team) { return GameRules_GetProp("m_bTeamReady", 1, .element = team) != 0; } public void ReadyTeamTimer(Handle _timer, int team) { ReadyTeam(team); } public void ReadyTeam(int team) { GameRules_SetProp("m_bTeamReady", 1, _ , team, true); } public void UnReadyTeam(int team) { GameRules_SetProp("m_bTeamReady", 0, _ , team, true); } public void CheckWhitelist() { decl String:whitelist[128]; GetConVarString(CvarWhitelist, whitelist, sizeof(whitelist)); decl String:expected[128]; GetExpectedWhitelist(expected); if (strncmp(expected, whitelist, strlen(whitelist)) == 0) { PrintToChatAll("Warning, incorrect whitelist loaded for game mode: %s", whitelist); } } public GetExpectedWhitelist(String:whitelist[128]) { decl String:league[8]; decl String:gamemode[8]; whitelist = ""; if (strncmp("ugc", league, strlen(league)) == 0) { if (strncmp("9v9", gamemode, strlen(gamemode)) == 0) { whitelist = "cfg/item_whitelist_ugc_HL.txt"; } else if (strncmp("6v6", gamemode, strlen(gamemode)) == 0) { whitelist = "cfg/item_whitelist_ugc_6v6.txt"; } } else if (strncmp("etf2l", league, strlen(league)) == 0) { if (strncmp("9v9", gamemode, strlen(gamemode)) == 0) { whitelist = "cfg/etf2l_whitelist_9v9.txt"; } else if (strncmp("6v6", gamemode, strlen(gamemode)) == 0) { whitelist = "cfg/etf2l_whitelist_6v6.txt"; } } } public int OtherTeam(int team) { if (team == 2) { return 3; } else { return 2; } } public int ExpectedPlayerCount(String:gamemode[8]) { if (strcmp(gamemode, "9v9") == 0) { return 9; } else if (strcmp(gamemode, "6v6") == 0) { return 6; } else if (strcmp(gamemode, "4v4") == 0) { return 4; } else if (strcmp(gamemode, "2v2") == 0) { return 2; } else { return 0; } } public void ExpectedGameMode(int count, String:mode[8]) { if (count == 9 || count == 8) { mode = "9v9"; } else if (count == 5 || count == 6) { mode = "6v6"; } else if (count == 3 || count == 4) { mode = "4v4"; } else if (count == 2) { mode = "2v2"; } else { mode = "unknown"; } }