Skip to content

Commit b0917b3

Browse files
committed
Added Flask server as an interface to control tf2 servers. Added RGL, UGC and ETF2L config. Added all maps on Fakkelbrigade.eu. Created script to automatically load all map names
1 parent 8c24cb6 commit b0917b3

File tree

7 files changed

+346
-0
lines changed

7 files changed

+346
-0
lines changed

client/csm.cfg

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// callFEELD's (Competitive) Server Manager
2+
// verison 0.1
3+
4+
// Loading message
5+
echo "Loaded callFEELD's (Competitive) Server Manager.";
6+
7+
alias "csm" "echo [CSM] IMPORTANT: before you can use the commands please enter the rcon password.; echo Type...; echo rcon_password RCON_PASSOWRD; echo; echo -------------------; echo csm_help -> shows you the commands;"
8+
9+
// CSM_HELP
10+
alias "csm_help" "echo ; echo ; echo callFEELD's (Competitive) Server Manager; echo v0.1; echo Check out the changelog and possible new versions on GitHub - github.com/callFEELD/CompetitiveServerManager; echo; echo Commands:; echo; echo csm_enable; echo; echo csm_disable; echo; echo csm_reload_tournament; echo; echo csm_etf2l; echo; echo csm_ugc; echo; echo Write one of the commands into the console again to see more details.;"
11+
12+
alias "csm_enable" "echo [CSM] Enable Commands; echo; echo csm_enable_singleready; echo; echo csm_enable_teamready; echo; echo csm_enable_dm;"
13+
alias "csm_disable" "echo [CSM] Disable Commands; echo; echo csm_disable_dm;"
14+
15+
// Text Variables
16+
alias "csm_t_config" "echo [CSM] Executing config...;"
17+
18+
// Basic commands
19+
alias "csm_reload_tournament" "echo [CSM] Reloading the tournament...; rcon mp_tournament_restart;"
20+
alias "csm_enable_singleready" "echo [CSM] Enabling the single ready...; rcon mp_tournament_readymode 1;"
21+
alias "csm_enable_teamready" "echo [CSM] Enabling the team ready...; rcon mp_tournament_readymode 0;"
22+
23+
24+
// loading ETF2L aliases
25+
alias "csm_etf2l" "echo [CSM] Available ETF2L configs; echo; echo csm_etf2l_6; echo; echo csm_etf2l_9; echo; echo csm_etf2l_ultiduo; echo; echo csm_etf2l_bball; echo; echo csm_etf2l_goldencap;"
26+
27+
//6v6 ETF2L
28+
alias "csm_etf2l_6" "echo [CSM] Available ETF2L 6v6 configs; echo; echo csm_etf2l_6_5cp; echo; echo csm_etf2l_6_koth; echo; echo csm_etf2l_6_ctf; echo; echo csm_etf2l_6_stopwatch;"
29+
30+
alias "csm_etf2l_6_5cp" "csm_t_config; rcon exec etf2l_6v6_5cp; say [CSM] executed csm_etf2l_6_5cp;"
31+
alias "csm_etf2l_6_koth" "csm_t_config; rcon exec etf2l_6v6_koth; say [CSM] executed csm_etf2l_6_koth;"
32+
alias "csm_etf2l_6_ctf" "csm_t_config; rcon exec etf2l_6v6_ctf; say [CSM] executed csm_etf2l_6_ctf;"
33+
alias "csm_etf2l_6_stopwatch" "csm_t_config; rcon exec etf2l_6v6_stopwatch; say [CSM] executed csm_etf2l_6_stopwatch;"
34+
35+
//9v9 ETF2L
36+
alias "csm_etf2l_9" "echo [CSM] Available ETF2L 9v9 configs; echo; echo csm_etf2l_9_5cp; echo; echo csm_etf2l_9_koth; echo; echo csm_etf2l_9_ctf; echo; echo csm_etf2l_9_stopwatch;"
37+
38+
alias "csm_etf2l_9_5cp" "csm_t_config; rcon exec etf2l_9v9_5cp; say [CSM] executed csm_etf2l_9_5cp;"
39+
alias "csm_etf2l_9_koth" "csm_t_config; rcon exec etf2l_9v9_koth; say [CSM] executed csm_etf2l_9_koth;"
40+
alias "csm_etf2l_9_ctf" "csm_t_config; rcon exec etf2l_9v9_ctf; say [CSM] executed csm_etf2l_9_ctf;"
41+
alias "csm_etf2l_9_stopwatch" "csm_t_config; rcon exec etf2l_9v9_stopwatch; say [CSM] executed csm_etf2l_9_stopwatch;"
42+
43+
//Other ETF2L
44+
alias "csm_etf2l_ultiduo" "csm_t_config; rcon exec etf2l_ultiduo; say [CSM] executed csm_etf2l_ultiduo;"
45+
alias "csm_etf2l_bball" "csm_t_config; rcon exec etf2l_bball; say [CSM] executed csm_etf2l_bball;"
46+
alias "csm_etf2l_goldencap" "csm_t_config; rcon exec etf2l_golden_cap; say [CSM] executed csm_etf2l_goldencap;"
47+
48+
49+
// loading UGC aliases
50+
alias "csm_ugc" "echo [CSM] Available UGC configs; echo; echo csm_ugc_4; echo; echo csm_ugc_6; echo; echo csm_ugc_9;"
51+
//4v4 UGC
52+
alias "csm_ugc_4" "echo [CSM] Available UGC 4v4 configs; echo; echo csm_ugc_4_standard; echo; echo csm_ugc_4_standard_overtime; echo; echo csm_ugc_4_koth; echo; echo csm_ugc_4_koth_overtime; echo; echo csm_ugc_4_goldencap; echo; echo csm_ugc_4_stopwatch;"
53+
54+
alias "csm_ugc_4_standard" "csm_t_config; rcon exec ugc_4v_standard; say [CSM] executed csm_ugc_4_standard;"
55+
alias "csm_ugc_4_standard_overtime" "csm_t_config; rcon exec ugc_4v_standard_overtime; say [CSM] executed csm_ugc_4_standard_overtime;"
56+
alias "csm_ugc_4_koth" "csm_t_config; rcon exec ugc_4v_koth; say [CSM] executed csm_ugc_4_koth;"
57+
alias "csm_ugc_4_koth_overtime" "csm_t_config; rcon exec ugc_4v_koth_overtime; say [CSM] executed csm_ugc_4_koth_overtime;"
58+
alias "csm_ugc_4_goldencap" "csm_t_config; rcon exec ugc_4v_golden; say [CSM] executed csm_ugc_4_goldencap;"
59+
alias "csm_ugc_4_stopwatch" "csm_t_config; rcon exec ugc_4v_stopwatch; say [CSM] executed csm_ugc_4_stopwatch;"
60+
61+
//6v6 UGC
62+
alias "csm_ugc_6" "echo [CSM] Available UGC 6v6 configs; echo; echo csm_ugc_6_standard; echo; echo csm_ugc_6_standard_overtime; echo; echo csm_ugc_6_koth; echo; echo csm_ugc_6_koth_overtime; echo; echo csm_ugc_6_goldencap; echo; echo csm_ugc_6_stopwatch;"
63+
64+
alias "csm_ugc_6_standard" "csm_t_config; rcon exec ugc_6v_standard; say [CSM] executed csm_ugc_6_standard;"
65+
alias "csm_ugc_6_standard_overtime" "csm_t_config; rcon exec ugc_6v_standard_overtime; say [CSM] executed csm_ugc_6_standard_overtime;"
66+
alias "csm_ugc_6_koth" "csm_t_config; rcon exec ugc_6v_koth; say [CSM] executed csm_ugc_6_koth;"
67+
alias "csm_ugc_6_koth_overtime" "csm_t_config; rcon exec ugc_6v_koth_overtime; say [CSM] executed csm_ugc_6_koth_overtime;"
68+
alias "csm_ugc_6_goldencap" "csm_t_config; rcon exec ugc_6v_golden; say [CSM] executed csm_ugc_6_goldencap;"
69+
alias "csm_ugc_6_stopwatch" "csm_t_config; rcon exec ugc_6v_stopwatch; say [CSM] executed csm_ugc_6_stopwatch;"
70+
71+
//9v9 UGC
72+
alias "csm_ugc_9" "echo [CSM] Available UGC 9v9 configs; echo; echo csm_ugc_9_standard; echo; echo csm_ugc_9_koth; echo; echo csm_ugc_9_ctf; echo; echo csm_ugc_9_stopwatch;"
73+
74+
alias "csm_ugc_9_standard" "csm_t_config; rcon exec ugc_HL_standard; say [CSM] executed csm_ugc_9_standard;"
75+
alias "csm_ugc_9_koth" "csm_t_config; rcon exec ugc_HL_koth; say [CSM] executed csm_ugc_9_koth;"
76+
alias "csm_ugc_9_ctf" "csm_t_config; rcon exec ugc_HL_ctf; say [CSM] executed csm_ugc_9_ctf;"
77+
alias "csm_ugc_9_stopwatch" "csm_t_config; rcon exec ugc_HL_stopwatch; say [CSM] executed csm_ugc_9_stopwatch;"
78+
79+
80+
// Enable/Disable SOAP DM Mod
81+
alias "csm_disable_dmmod" "echo [CSM] Disabling SOAP DM Mod on the server...; rcon sm plugins unload soap_tf2dm; csm_reload_tournament; say [CSM] disabled SOAP DM Mod;"
82+
alias "csm_enable_dmmod" "echo [CSM] Enabling SOAP DM Mod on the server...; rcon sm plugins load soap_tf2dm; csm_reload_tournament; say [CSM] enabled SOAP DM Mod;"
83+
alias "csm_disable_soap" "csm_disable_dmmod"
84+
alias "csm_enable_soap" "csm_enable_dmmod"
85+
alias "csm_enable_dm" "csm_enable_dmmod"
86+
alias "csm_disable_dm" "csm_disable_dmmod"

server/api_server.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from flask import Flask, request, jsonify
2+
3+
import rcon_connector as rcon
4+
5+
app = Flask(__name__)
6+
7+
VERSION = 0.1
8+
9+
SUCCESS_STATUS = 200
10+
11+
class ERROR():
12+
AUTHENTICATE_ERROR = {
13+
"status": 500,
14+
"version": VERSION
15+
}
16+
FAILURE_STATUS = {
17+
"status": 400,
18+
"version": VERSION
19+
}
20+
21+
22+
# Server Info
23+
@app.route('/info', methods = ['POST'])
24+
def info():
25+
address = request.form['server_address']
26+
port = request.form['server_port']
27+
result = rcon.get_server_info(address, port)
28+
return api_return_handler(result)
29+
30+
31+
# Control commands
32+
@app.route('/control/<command>', methods = ['POST'])
33+
def control(command):
34+
command = command.lower()
35+
36+
# authenticate
37+
address = request.form['server_address']
38+
port = request.form['server_port']
39+
password = request.form['server_password']
40+
41+
if address is not None and port is not None and password is not None:
42+
if command == 'disable_mge':
43+
result = rcon.rcon_connect(address, port, password, rcon.RCON_COMMAND.DISABLE_MGE)
44+
return api_return_handler(result)
45+
elif command == 'enable_mge':
46+
result = rcon.rcon_connect(address, port, password, rcon.RCON_COMMAND.ENABLE_MGE)
47+
return api_return_handler(result)
48+
elif command == 'single_readyup':
49+
result = rcon.rcon_connect(address, port, password, rcon.RCON_COMMAND.SINGLE_READYUP)
50+
return api_return_handler(result)
51+
elif command == 'team_readyup':
52+
result = rcon.rcon_connect(address, port, password, rcon.RCON_COMMAND.TEAM_READYUP)
53+
return api_return_handler(result)
54+
else:
55+
return jsonify(ERROR.AUTHENTICATE_ERROR)
56+
57+
58+
59+
def api_return_handler(response):
60+
if response is None:
61+
return ERROR.FAILURE_STATUS
62+
63+
return jsonify({
64+
"status": SUCCESS_STATUS,
65+
"version": VERSION,
66+
"result": response
67+
})
68+
69+
70+
if __name__ == '__main__':
71+
app.run()

server/index.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<html>
2+
<body>
3+
<h1>Server Info</h1>
4+
<form action = "http://localhost:5000/info" method = "post">
5+
<p>Enter Name:</p>
6+
<p><input type = "text" name = "server_address" /></p>
7+
<p><input type = "text" name = "server_port" /></p>
8+
<p><input type = "submit" value = "submit" /></p>
9+
</form>
10+
<h1>Server RCON</h1>
11+
<form action = "http://localhost:5000/control/disable_mge" method = "post">
12+
<p>Enter Name:</p>
13+
<p><input type = "text" name = "server_address" /></p>
14+
<p><input type = "text" name = "server_port" /></p>
15+
<p><input type = "text" name = "server_password" /></p>
16+
<p><input type = "submit" value = "submit" /></p>
17+
</form>
18+
</body>
19+
</html>

server/league_configs.json

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"ETF2L": [
3+
"etf2l",
4+
5+
"etf2l_6v6",
6+
"etf2l_6v6_5cp",
7+
"etf2l_6v6_ctf",
8+
"etf2l_6v6_koth",
9+
"etf2l_6v6_stopwatch",
10+
11+
"etf2l_9v9",
12+
"etf2l_9v9_5cp",
13+
"etf2l_9v9_ctf",
14+
"etf2l_9v9_koth",
15+
"etf2l_9v9_stopwatch",
16+
17+
"etf2l_bball",
18+
"etf2l_custom",
19+
"etf2l_golden_cap",
20+
"etf2l_ultiduo"
21+
],
22+
23+
"UGC": [
24+
"ugc_6v_standard",
25+
"ugc_6v_standard_overtime",
26+
"csm_ugc_6_koth",
27+
"ugc_6v_koth_overtime",
28+
"ugc_6v_golden",
29+
"ugc_6v_stopwatch",
30+
31+
"ugc_HL_standard",
32+
"ugc_HL_koth",
33+
"ugc_HL_ctf",
34+
"ugc_HL_stopwatch",
35+
36+
"ugc_4v_standard",
37+
"ugc_4v_standard_overtime",
38+
"ugc_4v_koth",
39+
"ugc_4v_koth_overtime",
40+
"ugc_4v_golden",
41+
"ugc_4v_stopwatch"
42+
],
43+
44+
"RGL": [
45+
"rgl_6s_5cp_scrim",
46+
"rgl_6s_5cp_match_half1",
47+
"rgl_6s_5cp_match_half2",
48+
"rgl_6s_5cp_gc",
49+
"rgl_6s_koth",
50+
"rgl_6s_koth_bo5",
51+
52+
"rgl_HL_stopwatch",
53+
"rgl_HL_koth",
54+
"rgl_HL_koth_bo5",
55+
56+
"rgl_7s_stopwatch",
57+
"rgl_7s_koth",
58+
"rgl_7s_koth_bo5",
59+
60+
"rgl_mm_5cp",
61+
"rgl_mm_stopwatch",
62+
"rgl_mm_koth",
63+
"rgl_mm_koth_bo5"
64+
]
65+
66+
}

server/maps.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

server/maps_grabber.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
This file grabs all map names from Fakkelbrigade.eu map list
3+
"""
4+
5+
import requests
6+
from bs4 import BeautifulSoup
7+
import json
8+
9+
URL = "http://fakkelbrigade.eu/maps"
10+
MAPS = []
11+
12+
page = requests.get(URL)
13+
soup = BeautifulSoup(page.content, 'html.parser')
14+
15+
rows = soup.find_all('tr')
16+
17+
for count, row in enumerate(rows):
18+
cells = row.find_all('td')
19+
20+
if len(cells) > 0:
21+
MAPS.append((cells[1].a.text.split('.')[0].lower()))
22+
23+
MAPS = list(set(MAPS))
24+
MAPS.sort()
25+
26+
with open("maps.json", "w") as file:
27+
file.write(json.dumps(MAPS))

server/rcon_connector.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""
2+
This file will manage the RCON connection to the server
3+
"""
4+
5+
import valve.rcon
6+
import valve.source.a2s
7+
8+
class RCON_COMMAND():
9+
DISABLE_MGE = "sm plugins unload soap_tf2dm; mp_tournament_restart;"
10+
ENABLE_MGE = "sm plugins load soap_tf2dm; mp_tournament_restart;"
11+
TOURNAMENT_RESTART = "mp_tournament_restart;"
12+
SINGLE_READYUP = "mp_tournament_readymode 1;"
13+
TEAM_READYUP = "mp_tournament_readymode 0;"
14+
15+
16+
def get_server_info(server_address, server_port):
17+
try:
18+
server_address = (server_address, int(server_port))
19+
20+
# Server details
21+
with valve.source.a2s.ServerQuerier(server_address, timeout=3.0) as server:
22+
info = server.info()
23+
player_count = server.players()["player_count"]
24+
25+
print(f"Server Name: {info['server_name']}")
26+
print(f"Players: {player_count} / {info['max_players']}")
27+
#print(f"Ping: {ping}")
28+
print(f"Map: {info['map']}")
29+
print(f"Password protected: {info['password_protected']}")
30+
print(f"Game: {info['game']}")
31+
return {
32+
"server_name": info['server_name'],
33+
"game": info['game'],
34+
"map": info['map'],
35+
"player_count": info['player_count'],
36+
"max_players": info['max_players']
37+
}
38+
return None
39+
except Exception as e:
40+
print(e)
41+
return None
42+
43+
# RCON connection with command
44+
def rcon_connect(server_address, server_port, server_password, command):
45+
try:
46+
server_address = (server_address, int(server_port))
47+
48+
with valve.rcon.RCON(server_address, server_password, timeout=5.0) as rcon:
49+
response = rcon(f"{command}")
50+
return {
51+
"status": 200,
52+
"message": "OK",
53+
"server_response": response
54+
}
55+
except ConnectionRefusedError:
56+
print("Server refused connection")
57+
return {
58+
"status": 400,
59+
"message": "Server refused connection"
60+
}
61+
except valve.rcon.RCONAuthenticationError:
62+
print("Wrong RCON authentication")
63+
return {
64+
"status": 400,
65+
"message": "Wrong RCON password"
66+
}
67+
except TimeoutError:
68+
return {
69+
"status": 400,
70+
"message": "Server timeed out"
71+
}
72+
except Exception as e:
73+
return {
74+
"status": 400,
75+
"message": "Unknow error"
76+
}

0 commit comments

Comments
 (0)