diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..412b9ab --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "sourcemod_plugin/get5-webapi"] + path = sourcemod_plugin/get5-webapi + url = https://github.com/PhlexPlexico/get5-webapi + branch = master diff --git a/README.md b/README.md index 6e7310f..78520e5 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![GitHub Downloads](https://img.shields.io/github/downloads/phlexplexico/get5-web/total.svg?label=Downloads)](https://github.com/phlexplexico/get5-web/releases/latest) --- -**Status: Supported** - +**Status: NOT Supported - End of Life Jan. 2020** +_As of January 1st, 2020, this application will no longer be supported with any updates. Issues will be created to help assist setup and point out any bugs. If someone would like to take over, please make a fork and make some PRs to fix any issues. If you would even like, merge them back here with a link to your fork in the README. Thank you everyone for finding this web panel, and I hope you still find use for this old technology. Some new development is coming down the pipe elsewhere, which I hope will help other developers make their own implementations of get5-web._ This is a web panel meant to be used in conjunction with the [get5](https://github.com/splewis/get5) CS:GO server plugin. It provides a more convenient way of managing matches and match servers. **This webpanel is intended for competitive 5v5 leagues and scrims, and nothing more.** @@ -19,11 +19,16 @@ _IF YOU HAVE ANY ISSUES WITH THE WEBPANEL OR THE API_STATS PLUGIN, **PLEASE REPO ## How to use it: -1a. Download the new get5_apistats.smx from the [releases](https://github.com/PhlexPlexico/get5-web/releases) page. -1b. Create your game servers on the "Add a server" page by giving their ip, port, and rcon password -2. Create teams on the "Create a Team" page by listing the steamids for each of the players -3. Go to the "Create a Match" page, selecting the teams, server, and rules for the match -4. Optional - Create a season with a given date range to keep track for a subset of matches. +1. Download the new get5_apistats.smx from the [releases](https://github.com/PhlexPlexico/get5-web/releases) page. + +2. Create your game servers on the "Add a server" page by giving their ip, port, and rcon password + +3. Create teams on the "Create a Team" page by listing the steamids for each of the players + +4. Go to the "Create a Match" page, selecting the teams, server, and rules for the match + +5. Optional - Create a season with a given date range to keep track for a subset of matches. + Once you do this, the site will send an rcon command to the game server `get5_loadmatch_url /match//config`, which will load the match config onto the gameserver automatically for you. Stats and game status will automatically be updated on the webpage. @@ -58,7 +63,9 @@ Please see the [installation instructions](https://github.com/PhlexPlexico/get5- ## How do the game server and web panel communicate? 1. When a server is added the web server will send `get5_web_avaliable` command through rcon that will check for the appropriate get5 plugins to be installed on the server + 2. When a match is assigned to a server, the `get5_loadmatch_url` command is used through rcon to tell the websever a file to download the get5 match config from + 3. When stats begin to update (map start, round end, map end, series end), the game server plugins will send HTTP requests to the web server, using a per-match API token set in the `get5_web_api_key` cvar when the match was assigned to the server ## Other useful commands: diff --git a/get5/get5_test.py b/get5/get5_test.py index 9cac259..f43e4b9 100644 --- a/get5/get5_test.py +++ b/get5/get5_test.py @@ -47,7 +47,7 @@ def create_test_data(self): db.session.commit() Match.create(user, team1.id, team2.id, '', '', 1, False, - 'Map {MAPNUMBER}', ['de_dust2', 'de_cache', 'de_mirage'], season.id, 'always_knife', 'CT', server.id, 0, 0, None, False, False) + 'Map {MAPNUMBER}', ['de_dust2', 'de_cache', 'de_mirage'], season.id, 'always_knife', 'CT', server.id, 0, 0, None, False, False, 5) db.session.commit() vetoBan = Veto.create(1, 'EnvyUs', 'de_dust2', 'ban') diff --git a/get5/match.py b/get5/match.py index b9aed93..6e0cc66 100755 --- a/get5/match.py +++ b/get5/match.py @@ -4,7 +4,7 @@ import steamid import get5 from get5 import app, db, BadRequestError, config_setting -from models import User, Team, Match, GameServer, Season, Veto, match_audit, MapStats, PlayerStats +from models import User, Team, Match, GameServer, Season, Veto, match_audit, MapStats, PlayerStats, MatchSpectator from collections import OrderedDict from datetime import datetime import util @@ -30,7 +30,7 @@ class MultiCheckboxField(SelectMultipleField): def different_teams_validator(form, field): if form.team1_id.data == form.team2_id.data: raise ValidationError('Teams cannot be equal') - + def mappool_validator(form, field): if 'preset' in form.series_type.data and len(form.veto_mappool.data) != 1: @@ -136,6 +136,10 @@ class MatchForm(Form): enforce_teams = BooleanField('Enforce Auths on Team', default=True) + min_player_ready = IntegerField('Max # Players Per Team', + default=5, + validators=[validators.required(), validators.NumberRange(1, 10)]) + def add_teams(self, user): if self.team1_id.choices is None: self.team1_id.choices = [] @@ -180,7 +184,11 @@ def add_seasons(self): self.season_selection.choices = [] season_tuples = [] season_tuples.append((0, 'No Season')) - for seasons in Season.query.filter((Season.end_date >= datetime.now()) | (Season.end_date.is_(None))).order_by(-Season.id): + if g.user.super_admin or g.user.admin: + ourSeasons = Season.query.filter((Season.end_date >= datetime.now()) | (Season.end_date.is_(None))).order_by(-Season.id) + else: + ourSeasons = Season.query.filter((Season.end_date >= datetime.now()) | (Season.end_date.is_(None))).filter(Season.user_id == g.user.id).order_by(-Season.id) + for seasons in ourSeasons: season_tuples.append((seasons.id, seasons.name)) self.season_selection.choices += season_tuples @@ -200,7 +208,7 @@ def match_create(): max_matches = config_setting('USER_MAX_MATCHES') season_id = None - if max_matches >= 0 and num_matches >= max_matches and not (util.is_admin(g.user) or util.is_super_admin(g.user)): + if max_matches >= 0 and num_matches >= max_matches and not (g.user.admin or g.user.super_admin): flash('You already have the maximum number of matches ({}) created'.format( num_matches)) @@ -266,7 +274,8 @@ def match_create(): season_id, form.data['side_type'], form.data['veto_first'], form.data['server_id'], team1_series_score, team2_series_score, specList, - form.data['private_match'], form.data['enforce_teams']) + form.data['private_match'], form.data['enforce_teams'], + form.data['min_player_ready']) # Save plugin version data if we have it if json_reply and 'plugin_version' in json_reply: @@ -277,6 +286,12 @@ def match_create(): server.in_use = True db.session.commit() + + # Implement normalized spectator list. + if specList: + for singleAuth in specList: + MatchSpectator.set_or_create(match.id, auth) + app.logger.info('User {} created match {}, assigned to server {}' .format(g.user.id, match.id, server.id)) @@ -298,7 +313,7 @@ def match_create(): @match_blueprint.route('/match//forfeit/') def match_forfeit(matchid, teamwinner): match = Match.query.get_or_404(matchid) - super_admintools_check(g.user, match) + super_admintools_check(match) if teamwinner == 1: winnerId = match.team1_id elif teamwinner == 2: @@ -346,7 +361,7 @@ def match(matchid): server = None team1 = Team.query.get_or_404(match.team1_id) team2 = Team.query.get_or_404(match.team2_id) - check_private_or_public(g.user, match, team1, team2) + check_private_or_public(match, team1, team2) map_stat_list = match.map_stats.all() completed = match.winner @@ -374,8 +389,8 @@ def match(matchid): if g.user: is_match_owner = (g.user.id == match.user_id) has_admin_access = (config_setting( - 'ADMINS_ACCESS_ALL_MATCHES') and util.is_admin(g.user)) - has_super_admin_access = util.is_super_admin(g.user) + 'ADMINS_ACCESS_ALL_MATCHES') and g.user.admin) + has_super_admin_access = g.user.super_admin is_server_op = util.is_server_owner(g.user, server) return render_template( 'match.html', user=g.user, admin_access=has_admin_access, @@ -398,7 +413,7 @@ def merge(a, b): match = Match.query.get_or_404(matchid) team1 = Team.query.get_or_404(match.team1_id) team2 = Team.query.get_or_404(match.team2_id) - check_private_or_public(g.user, match, team1, team2) + check_private_or_public(match, team1, team2) map_num = 0 map_stat_list = match.map_stats.all() player_dict = {} @@ -448,7 +463,7 @@ def match_config(matchid): def match_cancel(matchid): app.logger.info("Match server id is: {}".format(matchid)) match = Match.query.get_or_404(matchid) - admintools_check(g.user, match) + admintools_check(match) match.cancelled = True server = GameServer.query.get(match.server_id) @@ -472,10 +487,11 @@ def match_rcon(matchid): command = request.values.get('command') server = GameServer.query.get_or_404(match.server_id) owns_server = util.is_server_owner(g.user, server) - is_sadmin = util.is_super_admin(g.user) + is_sadmin = g.user.super_admin # Check to see if user owns server. - if not owns_server or not is_sadmin: - raise BadRequestError('You are not the server owner.') + if not owns_server: + if not is_sadmin: + raise BadRequestError('You are not the server owner.') if command: try: @@ -499,7 +515,7 @@ def match_rcon(matchid): @match_blueprint.route('/match//pause') def match_pause(matchid): match = Match.query.get_or_404(matchid) - admintools_check(g.user, match) + admintools_check(match) server = GameServer.query.get_or_404(match.server_id) try: @@ -514,7 +530,7 @@ def match_pause(matchid): @match_blueprint.route('/match//unpause') def match_unpause(matchid): match = Match.query.get_or_404(matchid) - admintools_check(g.user, match) + admintools_check(match) server = GameServer.query.get_or_404(match.server_id) try: @@ -529,7 +545,8 @@ def match_unpause(matchid): @match_blueprint.route('/match//adduser') def match_adduser(matchid): match = Match.query.get_or_404(matchid) - admintools_check(g.user, match) + app.logger.info("Our user: {}".format(g.user)) + admintools_check(match) server = GameServer.query.get_or_404(match.server_id) team = request.values.get('team') if not team: @@ -542,6 +559,8 @@ def match_adduser(matchid): command = 'get5_addplayer {} {}'.format(new_auth, team) response = server.send_rcon_command(command, raise_errors=True) match_audit.create(g.user.id, matchid, datetime.now(), command) + if (team == "spec"): + MatchSpectator.set_or_create(matchid, new_auth) db.session.commit() flash(response) except util.RconError as e: @@ -556,7 +575,7 @@ def match_adduser(matchid): @match_blueprint.route('/match//backup', methods=['GET']) def match_backup(matchid): match = Match.query.get_or_404(matchid) - admintools_check(g.user, match) + admintools_check(match) server = GameServer.query.get_or_404(match.server_id) file = request.values.get('file') @@ -581,9 +600,9 @@ def match_backup(matchid): flash('Restored backup file {}'.format(file)) else: flash('Failed to restore backup file {}'.format(file)) - return redirect('match/{}/backup'.format(matchid)) + return redirect('/match/{}/backup'.format(matchid)) - return redirect('match/{}'.format(matchid)) + return redirect('/match/{}'.format(matchid)) @match_blueprint.route("/matches") @@ -624,6 +643,7 @@ def delete_cancelled_matches(): PlayerStats.query.filter_by(match_id=match.id).delete() MapStats.query.filter_by(match_id=match.id).delete() Veto.query.filter_by(match_id=match.id).delete() + MatchSpectator.query.filter_by(match_id=match.id).delete() matches.delete() db.session.commit() return redirect('/matches/' + str(g.user.id)) @@ -662,11 +682,11 @@ def generate(): # Begin Helper Functions -def super_admintools_check(user, match): - if user is None: +def super_admintools_check(match): + if not g.user: raise BadRequestError('You do not have access to this page') - if not util.is_super_admin(user): + if not g.user.super_admin: raise BadRequestError('You do not have access to this page') if match.finished(): @@ -676,13 +696,13 @@ def super_admintools_check(user, match): raise BadRequestError('Match is cancelled') -def admintools_check(user, match): - if user is None: +def admintools_check(match): + if not g.user: raise BadRequestError('You do not have access to this page') - grant_admin_access = util.is_admin(user) and get5.config_setting( + grant_admin_access = (g.user.admin or g.user.super_admin) and get5.config_setting( 'ADMINS_ACCESS_ALL_MATCHES') - if user.id != match.user_id and not grant_admin_access: + if g.user.id != match.user_id and not grant_admin_access: raise BadRequestError('You do not have access to this page') if match.finished(): @@ -691,24 +711,24 @@ def admintools_check(user, match): if match.cancelled: raise BadRequestError('Match is cancelled') -def check_private_or_public(user, match, team1, team2): +def check_private_or_public(match, team1, team2): if match.is_private_match(): - if not user: + if not g.user: raise BadRequestError("Please login before viewing this match.") # Get team lists, and check if logged in user is part of match. - if (user.id == match.user_id) or (config_setting( - 'ADMINS_ACCESS_ALL_MATCHES') and util.is_admin(user)) or util.is_super_admin(user): + if (g.user.id == match.user_id) or (config_setting( + 'ADMINS_ACCESS_ALL_MATCHES') and g.user.admin) or g.user.super_admin: isPlayer = False playerstats_steam = [r.steam_id for r in PlayerStats.query.filter( PlayerStats.match_id == match.id)] playerList = list( set(team1.auths + team2.auths + playerstats_steam)) app.logger.info("Our list: {}".format(playerList)) - if (config_setting('ADMINS_ACCESS_ALL_MATCHES') and util.is_admin(user)) or util.is_super_admin(user): + if (config_setting('ADMINS_ACCESS_ALL_MATCHES') and g.user.admin) or g.user.super_admin: isPlayer = True else: for player in playerList: - if user.steam_id == player: + if g.user.steam_id == player: isPlayer = True break if not isPlayer: diff --git a/get5/models.py b/get5/models.py index 7dfd886..5ebd053 100755 --- a/get5/models.py +++ b/get5/models.py @@ -52,8 +52,8 @@ def get_recent_matches(self, limit=10): return self.matches.filter_by(cancelled=False).limit(limit) def __repr__(self): - return 'User(id={}, steam_id={}, name={}, admin={})'.format( - self.id, self.steam_id, self.name, self.admin) + return 'User(id={}, steam_id={}, name={}, admin={}, super_admin={})'.format( + self.id, self.steam_id, self.name, self.admin, self.super_admin) class GameServer(db.Model): @@ -135,7 +135,7 @@ def create(user, name, tag, flag, logo, auths, public_team=False, preferred_name rv = Team() rv.user_id = user.id rv.set_data(name, tag, flag, logo, auths, - (public_team and util.is_admin(user)), preferred_names) + (public_team and user.admin), preferred_names) db.session.add(rv) return rv @@ -153,7 +153,7 @@ def can_edit(self, user): return False if self.user_id == user.id: return True - if util.is_super_admin(user): + if user.super_admin: return True return False @@ -261,6 +261,29 @@ def __repr__(self): return 'Team(id={}, user_id={}, name={}, flag={}, logo={}, public={})'.format( self.id, self.user_id, self.name, self.flag, self.logo, self.public_team) +class TeamAuthNames(db.Model): + id = db.Column(db.Integer, primary_key=True) + team_id = db.Column(db.Integer, db.ForeignKey('team.id')) + auth = db.Column(db.String(17)) + name = db.Column(db.String(40)) + + @staticmethod + def set_or_create(team_id, auth, name): + rv = TeamAuthNames.query.filter_by(team_id=team_id,auth=auth).first() + if rv is None: + rv = TeamAuthNames() + rv.set_data(team_id, auth, name) + db.session.add(rv) + else: + rv.set_data(team_id, auth, name) + return rv + + def set_data(self, team_id, auth, name): + self.team_id = team_id + self.auth = auth + self.name = name if name else '' + + class Season(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -294,7 +317,7 @@ def can_edit(self, user): return False if self.user_id == user.id: return True - if util.is_super_admin(user): + if user.super_admin: return True return False @@ -376,12 +399,13 @@ class Match(db.Model): spectator_auths = db.Column(db.PickleType) private_match = db.Column(db.Boolean) enforce_teams = db.Column(db.Boolean, default=True) + min_player_ready = db.Column(db.Integer, default=5) @staticmethod def create(user, team1_id, team2_id, team1_string, team2_string, max_maps, skip_veto, title, veto_mappool, season_id, side_type, veto_first, server_id=None, team1_series_score=None, team2_series_score=None, - spectator_auths=None, private_match=False, enforce_teams=True): + spectator_auths=None, private_match=False, enforce_teams=True, min_player_ready=5): rv = Match() rv.user_id = user.id rv.team1_id = team1_id @@ -406,6 +430,7 @@ def create(user, team1_id, team2_id, team1_string, team2_string, rv.spectator_auths = spectator_auths rv.private_match = private_match rv.enforce_teams = enforce_teams + rv.min_player_ready = min_player_ready db.session.add(rv) return rv @@ -544,13 +569,19 @@ def build_match_dict(self): d['match_title'] = self.title d['side_type'] = self.side_type d['veto_first'] = self.veto_first - d['skip_veto'] = self.skip_veto if self.max_maps == 2: d['bo2_series'] = True else: d['maps_to_win'] = self.max_maps / 2 + 1 + try: + d['min_players_to_ready'] = self.min_player_ready + d['players_per_team'] = self.min_player_ready + except: + d['min_players_to_ready'] = 5 + d['players_per_team'] = 5 + def add_team_data(teamkey, teamid, matchtext): team = Team.query.get(teamid) if not team: @@ -618,6 +649,26 @@ def __repr__(self): return 'Match(id={})'.format(self.id) +class MatchSpectator(db.Model): + id = db.Column(db.Integer, primary_key=True) + match_id = db.Column(db.Integer, db.ForeignKey('match.id')) + auth = db.Column(db.String(17)) + + @staticmethod + def set_or_create(match_id, auth): + rv = MatchSpectator.query.filter_by(match_id=match_id,auth=auth).first() + if rv is None: + rv = MatchSpectator() + rv.set_data(match_id, auth) + db.session.add(rv) + else: + rv.set_data(match_id, auth) + return rv + + def set_data(self, match_id, auth): + self.match_id = match_id + self.auth = auth + class MapStats(db.Model): id = db.Column(db.Integer, primary_key=True) match_id = db.Column(db.Integer, db.ForeignKey('match.id')) diff --git a/get5/season.py b/get5/season.py index 124dc9b..4f894a5 100755 --- a/get5/season.py +++ b/get5/season.py @@ -58,7 +58,7 @@ def season_create(): if request.method == 'POST': num_seasons = g.user.seasons.count() max_seasons = config_setting('USER_MAX_SEASONS') - if max_seasons >= 0 and num_seasons >= max_seasons and not (util.is_admin(g.user) or util.is_super_admin(g.user)): + if max_seasons >= 0 and num_seasons >= max_seasons and not (g.user.admin or g.user.super_admin): flash('You already have the maximum number of seasons ({}) created'.format( num_seasons)) @@ -94,9 +94,11 @@ def season_matches(seasonid): def seasons_user(userid): user = User.query.get_or_404(userid) seasons = user.seasons.order_by(-Season.id) + seasoned_matches = Match.query.filter(Match.season_id.isnot(None), Match.cancelled==False) is_owner = (g.user is not None) and (userid == g.user.id) return render_template('seasons.html', user=g.user, seasons=seasons, - my_seasons=is_owner, all_matches=False, season_owner=user) + my_seasons=is_owner, all_matches=False, matches=seasoned_matches, + season_owner=user) @season_blueprint.route('/season//edit', methods=['GET', 'POST']) diff --git a/get5/server.py b/get5/server.py index 4a9df2f..7f77fa8 100755 --- a/get5/server.py +++ b/get5/server.py @@ -43,7 +43,7 @@ def server_create(): if request.method == 'POST': num_servers = g.user.servers.count() max_servers = config_setting('USER_MAX_SERVERS') - if max_servers >= 0 and num_servers >= max_servers and not (util.is_admin(g.user) or util.is_super_admin(g.user)): + if max_servers >= 0 and num_servers >= max_servers and not (g.user.admin or g.user.super_admin): flash('You already have the maximum number of servers ({}) stored'.format( num_servers)) @@ -59,7 +59,7 @@ def server_create(): data['display_name'], data['ip_string'], data['port'], encRcon, - data['public_server'] and util.is_admin(g.user)) + data['public_server'] and (g.user.admin or g.user.super_admin)) if mock or util.check_server_connection(server, dbKey): db.session.commit() @@ -74,15 +74,14 @@ def server_create(): flash_errors(form) return render_template('server_create.html', user=g.user, form=form, - edit=False, is_admin=util.is_admin(g.user)) + edit=False, is_admin=g.user.admin, is_sadmin=g.user.super_admin) @server_blueprint.route('/server//edit', methods=['GET', 'POST']) def server_edit(serverid): server = GameServer.query.get_or_404(serverid) is_owner = (g.user and (util.is_server_owner(g.user, server))) - is_sadmin = (g.user and util.is_super_admin(g.user)) - app.logger.info("Owner: {} Sadmin: {}".format(is_owner, is_sadmin)) + is_sadmin = (g.user and g.user.super_admin) if not is_owner: if not is_sadmin: raise BadRequestError('You do not have access to this server.') @@ -108,7 +107,7 @@ def server_edit(serverid): server.ip_string = data['ip_string'] server.port = data['port'] server.rcon_password = encRcon - server.public_server = (data['public_server'] and util.is_admin(g.user)) + server.public_server = (data['public_server'] and (g.user.admin or g.user.super_admin)) if mock or util.check_server_connection(server, dbKey): db.session.commit() @@ -121,14 +120,14 @@ def server_edit(serverid): flash_errors(form) return render_template('server_create.html', user=g.user, form=form, - edit=True, is_admin=util.is_admin(g.user), is_sadmin=util.is_super_admin(g.user)) + edit=True, is_admin=g.user.admin, is_sadmin=g.user.super_admin) @server_blueprint.route('/server//delete', methods=['GET']) def server_delete(serverid): server = GameServer.query.get_or_404(serverid) is_owner = g.user and (g.user.id == server.user_id) - is_sadmin = g.user and util.is_super_admin(g.user) + is_sadmin = g.user and g.user.super_admin if not is_owner: if not is_sadmin: raise BadRequestError('You do not have access to this server.') @@ -142,7 +141,7 @@ def server_delete(serverid): GameServer.query.filter_by(id=serverid).delete() db.session.commit() - return redirect('myservers') + return redirect('/myservers') @server_blueprint.route("/myservers") @@ -152,7 +151,7 @@ def myservers(): servers = GameServer.query.filter_by( user_id=g.user.id).order_by(-GameServer.id).limit(50) - if util.is_super_admin(g.user): + if g.user.super_admin: servers = GameServer.query.order_by(-GameServer.id) return render_template('servers.html', user=g.user, servers=servers) diff --git a/get5/team.py b/get5/team.py index 8df9fe2..bef702a 100755 --- a/get5/team.py +++ b/get5/team.py @@ -1,6 +1,7 @@ from get5 import app, db, flash_errors, config_setting, BadRequestError -from models import User, Team +from models import User, Team, TeamAuthNames +import itertools import countries import logos import steamid @@ -44,7 +45,7 @@ def valid_file(form, field): mock = config_setting("TESTING") if mock: return - elif not util.is_admin(g.user): + elif not g.user.admin: return filename = secure_filename(field.data.filename) # Safe method. @@ -167,7 +168,7 @@ def team_create(): if request.method == 'POST': num_teams = g.user.teams.count() max_teams = config_setting('USER_MAX_TEAMS') - if max_teams >= 0 and num_teams >= max_teams and not (util.is_admin(g.user) or util.is_super_admin(g.user)): + if max_teams >= 0 and num_teams >= max_teams and not (g.user.admin or g.user.super_admin): flash( 'You already have the maximum number of teams ({}) stored'.format(num_teams)) @@ -182,7 +183,7 @@ def team_create(): # Update the logo. Passing validation we have the filename in the # list now. - if not mock and (util.is_admin(g.user) or util.is_super_admin(g.user)) and form.upload_logo.data: + if not mock and (g.user.admin or g.user.super_admin) and form.upload_logo.data: filename = secure_filename(form.upload_logo.data.filename) index_of_dot = filename.index('.') newLogoDetail = filename[:index_of_dot] @@ -192,7 +193,12 @@ def team_create(): data['logo'] = newLogoDetail team = Team.create(g.user, name, tag, flag, logo, - auths, data['public_team'] and (util.is_admin(g.user) or util.is_super_admin(g.user)), pref_names) + auths, data['public_team'] and (g.user.admin or g.user.super_admin), pref_names) + db.session.commit() + + for auth,name in itertools.izip_longest(auths,pref_names): + if auth: + TeamAuthNames.set_or_create(team.id, auth, name) db.session.commit() app.logger.info( @@ -204,7 +210,7 @@ def team_create(): flash_errors(form) return render_template('team_create.html', user=g.user, form=form, - edit=False, is_admin=(util.is_admin(g.user) or util.is_super_admin(g.user)), MAXPLAYER=Team.MAXPLAYERS, customNames=customNames) + edit=False, is_admin=(g.user.admin or g.user.super_admin), MAXPLAYER=Team.MAXPLAYERS, customNames=customNames) @team_blueprint.route('/team/', methods=['GET']) @@ -245,28 +251,33 @@ def team_edit(teamid): field.data = None form.public_team.data = team.public_team return render_template('team_create.html', user=g.user, form=form, - edit=True, is_admin=util.is_admin(g.user), MAXPLAYER=Team.MAXPLAYERS, customNames=customNames) + edit=True, is_admin=(g.user.admin or g.user.super_admin), MAXPLAYER=Team.MAXPLAYERS, customNames=customNames) elif request.method == 'POST': if form.validate(): data = form.data public_team = team.public_team - if util.is_admin(g.user): + if (g.user.admin or g.user.super_admin): public_team = data['public_team'] # Update the logo. Passing validation we have the filename in the # list now. - if not mock and util.is_admin(g.user) and form.upload_logo.data: + if not mock and (g.user.admin or g.user.super_admin) and form.upload_logo.data: filename = secure_filename(form.upload_logo.data.filename) index_of_dot = filename.index('.') newLogoDetail = filename[:index_of_dot] # Reinit our logos. logos.add_new_logo(newLogoDetail) data['logo'] = newLogoDetail - + allAuths = form.get_auth_list() + allNames = form.get_pref_list() team.set_data(data['name'], data['tag'], data['country_flag'], - data['logo'], form.get_auth_list(), - public_team, form.get_pref_list()) + data['logo'], allAuths, + public_team, allNames) + for auth,name in itertools.izip_longest(allAuths,allNames): + if auth: + teamNames = TeamAuthNames.set_or_create(teamid, auth, name) + db.session.commit() return redirect('/teams/{}'.format(team.user_id)) @@ -275,7 +286,7 @@ def team_edit(teamid): return render_template( 'team_create.html', user=g.user, form=form, edit=True, - is_admin=util.is_admin(g.user), MAXPLAYER=Team.MAXPLAYERS) + is_admin=g.user.admin, MAXPLAYER=Team.MAXPLAYERS) @team_blueprint.route('/team//delete') @@ -284,8 +295,11 @@ def team_delete(teamid): if not team.can_delete(g.user): raise BadRequestError("Cannot delete this team.") + if TeamAuthNames.query.filter_by(team_id=teamid).delete(): + db.session.commit() if Team.query.filter_by(id=teamid).delete(): db.session.commit() + return redirect('/myteams') @@ -312,7 +326,7 @@ def teams_user(userid): else: # Render teams page - my_teams = (g.user is not None and ((userid == g.user.id) or util.is_super_admin(g.user))) + my_teams = (g.user is not None and ((userid == g.user.id) or g.user.super_admin)) teams = user.teams.paginate(page, 20) return render_template( 'teams.html', user=g.user, teams=teams, my_teams=my_teams, @@ -342,7 +356,7 @@ def all_teams(): else: # Render teams page teams = all_public_teams.paginate(page, 20) - editable = g.user is not None and util.is_super_admin(g.user) + editable = g.user is not None and g.user.super_admin return render_template( 'teams.html', user=g.user, teams=teams, my_teams=editable, page=page, owner=None) diff --git a/get5/templates/match_create.html b/get5/templates/match_create.html index 1c62fff..2df3945 100644 --- a/get5/templates/match_create.html +++ b/get5/templates/match_create.html @@ -160,6 +160,13 @@ +
+ {{ form.min_player_ready.label(class="col-sm-2 control-label") }} +
+ {{ form.min_player_ready(class="form-control input-sm") }} +
+
+
{{ form.spectator_string.label(class="col-sm-2 control-label") }}
@@ -190,4 +197,4 @@ }) -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/get5/util.py b/get5/util.py index 006ece9..5c81b33 100755 --- a/get5/util.py +++ b/get5/util.py @@ -187,14 +187,4 @@ def is_server_owner(user, server): else: return False -def is_super_admin(user): - if user is None: - return False - - return user.super_admin - -def is_admin(user): - if user is None: - return False - - return user.admin \ No newline at end of file + return bool(user.admin) diff --git a/migrations/versions/3d5477aad91e_.py b/migrations/versions/3d5477aad91e_.py new file mode 100644 index 0000000..17c667d --- /dev/null +++ b/migrations/versions/3d5477aad91e_.py @@ -0,0 +1,25 @@ +"""Update match to include min players to ready. + +Revision ID: 3d5477aad91e +Revises: f3e41326bbc5 +Create Date: 2019-12-05 11:29:05.315175 + +""" + +# revision identifiers, used by Alembic. +revision= '3d5477aad91e' +down_revision = 'f3e41326bbc5' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.add_column('match', sa.Column('min_player_ready', sa.Integer(), nullable=True, default=5)) + ### end Alembic commands ### + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_column('match', 'min_player_ready') + ### end Alembic commands ### diff --git a/migrations/versions/79a7336b76fc_.py b/migrations/versions/79a7336b76fc_.py new file mode 100644 index 0000000..9c60a1b --- /dev/null +++ b/migrations/versions/79a7336b76fc_.py @@ -0,0 +1,35 @@ +"""Create team auth normalized table. + +Revision ID: 79a7336b76fc +Revises: 254a3741efe3 +Create Date: 2019-10-28 17:59:01.716518 + +""" + +# revision identifiers, used by Alembic. +revision = '79a7336b76fc' +down_revision = '254a3741efe3' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_table('team_auth_names', + sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False), + sa.Column('team_id', mysql.INTEGER(display_width=11), nullable=False), + sa.Column('auth', mysql.VARCHAR(length=17), nullable=False), + sa.Column('name', mysql.VARCHAR(length=40), nullable=True), + sa.ForeignKeyConstraint(['team_id'], ['team.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_default_charset=u'utf8mb4', + mysql_engine=u'InnoDB' + ) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_table('team_auth_names') + ### end Alembic commands ### diff --git a/migrations/versions/f3e41326bbc5_.py b/migrations/versions/f3e41326bbc5_.py new file mode 100644 index 0000000..ccd3490 --- /dev/null +++ b/migrations/versions/f3e41326bbc5_.py @@ -0,0 +1,34 @@ +"""Update to normalize spectator auths, remove from using pickletypes. + +Revision ID: f3e41326bbc5 +Revises: 79a7336b76fc +Create Date: 2019-11-06 19:42:59.892408 + +""" + +# revision identifiers, used by Alembic. +revision = 'f3e41326bbc5' +down_revision = '79a7336b76fc' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_table('match_spectator', + sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False), + sa.Column('match_id', mysql.INTEGER(display_width=11), nullable=False), + sa.Column('auth', mysql.VARCHAR(length=17), nullable=False), + sa.ForeignKeyConstraint(['match_id'], ['match.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_default_charset=u'utf8mb4', + mysql_engine=u'InnoDB' + ) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_table('match_spectator') + ### end Alembic commands ### diff --git a/sourcemod_plugin/get5-webapi b/sourcemod_plugin/get5-webapi new file mode 160000 index 0000000..e41ac0a --- /dev/null +++ b/sourcemod_plugin/get5-webapi @@ -0,0 +1 @@ +Subproject commit e41ac0ab3c698ed67dbadcd667e55feef403e074 diff --git a/sourcemod_plugin/get5_apistats/.gitignore b/sourcemod_plugin/get5_apistats/.gitignore deleted file mode 100644 index a213ccc..0000000 --- a/sourcemod_plugin/get5_apistats/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.smx -*.zip -*.tar.gz -builds diff --git a/sourcemod_plugin/get5_apistats/scripting/.clang-format b/sourcemod_plugin/get5_apistats/scripting/.clang-format deleted file mode 100644 index 9205d19..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/.clang-format +++ /dev/null @@ -1,67 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: Google -AccessModifierOffset: -1 -AlignAfterOpenBracket: true -AlignConsecutiveAssignments: false -AlignEscapedNewlinesLeft: true -AlignOperands: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: true -BinPackArguments: true -BinPackParameters: true -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Attach -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakStringLiterals: false -ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DerivePointerAlignment: true -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IndentCaseLabels: true -IndentWidth: 2 -IndentWrappedFunctionNames: false -KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: false -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 100000000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left -SpaceAfterCStyleCast: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Auto -TabWidth: 8 -UseTab: Never -... diff --git a/sourcemod_plugin/get5_apistats/scripting/get5/jsonhelpers.sp b/sourcemod_plugin/get5_apistats/scripting/get5/jsonhelpers.sp deleted file mode 100644 index f038d61..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/get5/jsonhelpers.sp +++ /dev/null @@ -1,144 +0,0 @@ -stock JSON_Object json_load_file(const char[] path) { - File f = OpenFile(path, "r"); - char contents[8192]; - f.ReadString(contents, sizeof(contents)); - delete f; - return json_decode(contents); -} - -stock void json_string_type(JSON_CELL_TYPE type, char[] output, int maxlength) { - switch (type) { - case Type_Invalid: Format(output, maxlength, "invalid"); - case Type_String: Format(output, maxlength, "string"); - case Type_Int: Format(output, maxlength, "int"); - case Type_Float: Format(output, maxlength, "float"); - case Type_Bool: Format(output, maxlength, "bool"); - case Type_Null: Format(output, maxlength, "null"); - case Type_Object: Format(output, maxlength, "object"); - } -} - -stock bool json_has_key(JSON_Object json, const char[] key, JSON_CELL_TYPE expectedType) { - if (json == null) { - return false; - } else if (!json.HasKey(key)) { - return false; - } else { - // Perform type-checking. - JSON_CELL_TYPE actualType = json.GetKeyType(key); - if (actualType != expectedType) { - char expectedTypeStr[16]; - char actualTypeStr[16]; - json_string_type(expectedType, expectedTypeStr, sizeof(expectedTypeStr)); - json_string_type(actualType, actualTypeStr, sizeof(actualTypeStr)); - LogError("Type mismatch for key \"%s\", got %s when expected a %s", key, actualTypeStr, - expectedTypeStr); - return false; - } - return true; - } -} - -stock int json_object_get_string_safe(JSON_Object json, const char[] key, char[] buffer, int maxlength, - const char[] defaultValue = "") { - if (json_has_key(json, key, Type_String)) { - return json.GetString(key, buffer, maxlength); - } else { - return strcopy(buffer, maxlength, defaultValue); - } -} - -stock int json_object_get_int_safe(JSON_Object json, const char[] key, int defaultValue = 0) { - if (json_has_key(json, key, Type_Int)) { - return json.GetInt(key); - } else { - return defaultValue; - } -} - -stock bool json_object_get_bool_safe(JSON_Object json, const char[] key, bool defaultValue = false) { - if (json_has_key(json, key, Type_Bool)) { - return json.GetBool(key); - } else { - return defaultValue; - } -} - -stock float json_object_get_float_safe(JSON_Object json, const char[] key, float defaultValue = 0.0) { - if (json_has_key(json, key, Type_Float)) { - return json.GetFloat(key); - } else { - return defaultValue; - } -} - -// Used for parsing an Array[String] to a sourcepawn ArrayList of strings -stock int AddJsonSubsectionArrayToList(JSON_Object json, const char[] key, ArrayList list, - int maxValueLength) { - if (!json_has_key(json, key, Type_Object)) { - return 0; - } - - int count = 0; - JSON_Object array = json.GetObject(key); - if (array != null) { - char[] buffer = new char[maxValueLength]; - for (int i = 0; i < array.Length; i++) { - char keyAsString[64]; - array.GetIndexString(keyAsString, sizeof(keyAsString), i); - array.GetString(keyAsString, buffer, maxValueLength); - list.PushString(buffer); - count++; - } - array.Cleanup(); - } - return count; -} - -// Used for mapping a keyvalue section -stock int AddJsonAuthsToList(JSON_Object json, const char[] key, ArrayList list, - int maxValueLength) { - int count = 0; - // We handle two formats here: one where we get a array of steamids as strings, and in the - // 2nd format we have a map of steamid- > player name. - JSON_Object data = json.GetObject(key); - if (data != null) { - if (data.IsArray) { - char[] buffer = new char[maxValueLength]; - for (int i = 0; i < data.Length; i++) { - char keyAsString[64]; - data.GetIndexString(keyAsString, sizeof(keyAsString), i); - data.GetString(keyAsString, buffer, maxValueLength); - - char steam64[AUTH_LENGTH]; - if (ConvertAuthToSteam64(buffer, steam64)) { - list.PushString(steam64); - count++; - } - } - - } else { - StringMapSnapshot snap = data.Snapshot(); - char[] buffer = new char[maxValueLength]; - char name[MAX_NAME_LENGTH]; - for (int i = 0; i < snap.Length; i++) { - snap.GetKey(i, buffer, maxValueLength); - - // Skip json meta keys. - if (json_is_meta_key(buffer)) { - continue; - } - - data.GetString(buffer, name, sizeof(name)); - char steam64[AUTH_LENGTH]; - if (ConvertAuthToSteam64(buffer, steam64)) { - Get5_SetPlayerName(steam64, name); - list.PushString(steam64); - count++; - } - } - delete snap; - } - } - return count; -} diff --git a/sourcemod_plugin/get5_apistats/scripting/get5/util.sp b/sourcemod_plugin/get5_apistats/scripting/get5/util.sp deleted file mode 100644 index a900983..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/get5/util.sp +++ /dev/null @@ -1,709 +0,0 @@ -#include - -#define MAX_INTEGER_STRING_LENGTH 16 -#define MAX_FLOAT_STRING_LENGTH 32 -#define AUTH_LENGTH 64 - -// Dummy value for when we need to write a keyvalue string, but we don't care about he value. -// Trying to write an empty string often results in the keyvalue not being writte, so we use this. -#define KEYVALUE_STRING_PLACEHOLDER "__placeholder" - -static char _colorNames[][] = {"{NORMAL}", "{DARK_RED}", "{PINK}", "{GREEN}", - "{YELLOW}", "{LIGHT_GREEN}", "{LIGHT_RED}", "{GRAY}", - "{ORANGE}", "{LIGHT_BLUE}", "{DARK_BLUE}", "{PURPLE}"}; -static char _colorCodes[][] = {"\x01", "\x02", "\x03", "\x04", "\x05", "\x06", - "\x07", "\x08", "\x09", "\x0B", "\x0C", "\x0E"}; - -// Convenience macros. -#define LOOP_TEAMS(%1) for (MatchTeam %1 = MatchTeam_Team1; %1 < MatchTeam_Count; %1 ++) -#define LOOP_CLIENTS(%1) for (int %1 = 0; %1 <= MaxClients; %1 ++) - -// These match CS:GO's m_gamePhase values. -enum GamePhase { - GamePhase_FirstHalf = 2, - GamePhase_SecondHalf = 3, - GamePhase_HalfTime = 4, - GamePhase_PostGame = 5, -}; - -/** - * Returns the number of human clients on a team. - */ -stock int GetNumHumansOnTeam(int team) { - int count = 0; - for (int i = 1; i <= MaxClients; i++) { - if (IsPlayer(i) && GetClientTeam(i) == team) { - count++; - } - } - return count; -} - -stock int CountAlivePlayersOnTeam(int csTeam) { - int count = 0; - for (int i = 1; i <= MaxClients; i++) { - if (IsPlayer(i) && IsPlayerAlive(i) && GetClientTeam(i) == csTeam) { - count++; - } - } - return count; -} - -stock int SumHealthOfTeam(int team) { - int sum = 0; - for (int i = 1; i <= MaxClients; i++) { - if (IsPlayer(i) && IsPlayerAlive(i) && GetClientTeam(i) == team) { - sum += GetClientHealth(i); - } - } - return sum; -} - -/** - * Switches and respawns a player onto a new team. - */ -stock void SwitchPlayerTeam(int client, int team) { - if (GetClientTeam(client) == team) { - return; - } - - LogDebug("SwitchPlayerTeam %L to %d", client, team); - if (team > CS_TEAM_SPECTATOR) { - CS_SwitchTeam(client, team); - CS_UpdateClientModel(client); - CS_RespawnPlayer(client); - } else { - ChangeClientTeam(client, team); - } -} - -/** - * Returns if a client is valid. - */ -stock bool IsValidClient(int client) { - return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); -} - -stock bool IsPlayer(int client) { - return IsValidClient(client) && !IsFakeClient(client); -} - -stock bool IsAuthedPlayer(int client) { - return IsPlayer(client) && IsClientAuthorized(client); -} - -/** - * Returns the number of clients that are actual players in the game. - */ -stock int GetRealClientCount() { - int clients = 0; - for (int i = 1; i <= MaxClients; i++) { - if (IsPlayer(i)) { - clients++; - } - } - return clients; -} - -stock void Colorize(char[] msg, int size, bool stripColor = false) { - for (int i = 0; i < sizeof(_colorNames); i++) { - if (stripColor) { - ReplaceString(msg, size, _colorNames[i], "\x01"); // replace with white - } else { - ReplaceString(msg, size, _colorNames[i], _colorCodes[i]); - } - } -} - -stock void ReplaceStringWithInt(char[] buffer, int len, const char[] replace, int value, - bool caseSensitive = false) { - char intString[MAX_INTEGER_STRING_LENGTH]; - IntToString(value, intString, sizeof(intString)); - ReplaceString(buffer, len, replace, intString, caseSensitive); -} - -stock bool IsTVEnabled() { - ConVar tvEnabledCvar = FindConVar("tv_enable"); - if (tvEnabledCvar == null) { - LogError("Failed to get tv_enable cvar"); - return false; - } - return tvEnabledCvar.BoolValue; -} - -stock int GetTvDelay() { - if (IsTVEnabled()) { - return GetCvarIntSafe("tv_delay"); - } - return 0; -} - -stock bool Record(const char[] demoName) { - char szDemoName[256]; - strcopy(szDemoName, sizeof(szDemoName), demoName); - ReplaceString(szDemoName, sizeof(szDemoName), "\"", "\\\""); - ServerCommand("tv_record \"%s\"", szDemoName); - - if (!IsTVEnabled()) { - LogError( - "Autorecording will not work with current cvar \"tv_enable\"=0. Set \"tv_enable 1\" in server.cfg (or another config file) to fix this."); - return false; - } - - return true; -} - -stock void StopRecording() { - ServerCommand("tv_stoprecord"); - Call_StartForward(g_OnDemoFinished); - Call_PushString(g_DemoFileName); - Call_Finish(); -} - -stock bool InWarmup() { - return GameRules_GetProp("m_bWarmupPeriod") != 0; -} - -stock bool InOvertime() { - return GameRules_GetProp("m_nOvertimePlaying") != 0; -} - -stock bool InFreezeTime() { - return GameRules_GetProp("m_bFreezePeriod") != 0; -} - -stock void EnsurePausedWarmup() { - if (!InWarmup()) { - StartWarmup(); - } - - ServerCommand("mp_warmup_pausetimer 1"); - ServerCommand("mp_do_warmup_period 1"); - ServerCommand("mp_warmup_pausetimer 1"); -} - -stock void StartWarmup(bool indefiniteWarmup = true, int warmupTime = 60) { - ServerCommand("mp_do_warmup_period 1"); - ServerCommand("mp_warmuptime %d", warmupTime); - ServerCommand("mp_warmup_start"); - - // For some reason it needs to get sent twice. Ask Valve. - if (indefiniteWarmup) { - ServerCommand("mp_warmup_pausetimer 1"); - ServerCommand("mp_warmup_pausetimer 1"); - } -} - -stock void EndWarmup(int time = 0) { - if (time == 0) { - ServerCommand("mp_warmup_end"); - } else { - ServerCommand("mp_warmup_pausetimer 0"); - ServerCommand("mp_warmuptime %d", time); - } -} - -stock bool IsPaused() { - return GameRules_GetProp("m_bMatchWaitingForResume") != 0; -} - -// Pauses and returns if the match will automatically unpause after the duration ends. -stock bool Pause(int pauseTime = 0, int csTeam = CS_TEAM_NONE) { - if (pauseTime == 0 || csTeam == CS_TEAM_SPECTATOR || csTeam == CS_TEAM_NONE) { - ServerCommand("mp_pause_match"); - return false; - } else { - ServerCommand("mp_pause_match"); - if (csTeam == CS_TEAM_T) { - GameRules_SetProp("m_bTerroristTimeOutActive", true); - GameRules_SetPropFloat("m_flTerroristTimeOutRemaining", float(pauseTime)); - } else if (csTeam == CS_TEAM_CT) { - GameRules_SetProp("m_bCTTimeOutActive", true); - GameRules_SetPropFloat("m_flCTTimeOutRemaining", float(pauseTime)); - } - return true; - } -} - -stock void Unpause() { - ServerCommand("mp_unpause_match"); -} - -stock void RestartGame(int delay) { - ServerCommand("mp_restartgame %d", delay); -} - -stock bool IsClientCoaching(int client) { - return GetClientTeam(client) == CS_TEAM_SPECTATOR && - GetEntProp(client, Prop_Send, "m_iCoachingTeam") != 0; -} - -stock void UpdateCoachTarget(int client, int csTeam) { - SetEntProp(client, Prop_Send, "m_iCoachingTeam", csTeam); -} - -stock void SetTeamInfo(int csTeam, const char[] name, const char[] flag = "", - const char[] logo = "", const char[] matchstat = "", int series_score = 0) { - int team_int = (csTeam == CS_TEAM_CT) ? 1 : 2; - - char teamCvarName[MAX_CVAR_LENGTH]; - char flagCvarName[MAX_CVAR_LENGTH]; - char logoCvarName[MAX_CVAR_LENGTH]; - char textCvarName[MAX_CVAR_LENGTH]; - char scoreCvarName[MAX_CVAR_LENGTH]; - Format(teamCvarName, sizeof(teamCvarName), "mp_teamname_%d", team_int); - Format(flagCvarName, sizeof(flagCvarName), "mp_teamflag_%d", team_int); - Format(logoCvarName, sizeof(logoCvarName), "mp_teamlogo_%d", team_int); - Format(textCvarName, sizeof(textCvarName), "mp_teammatchstat_%d", team_int); - Format(scoreCvarName, sizeof(scoreCvarName), "mp_teamscore_%d", team_int); - - // Add Ready/Not ready tags to team name if in warmup. - char taggedName[MAX_CVAR_LENGTH]; - if ((g_GameState == Get5State_Warmup || g_GameState == Get5State_PreVeto) && - !g_DoingBackupRestoreNow) { - MatchTeam matchTeam = CSTeamToMatchTeam(csTeam); - if (IsTeamReady(matchTeam)) { - Format(taggedName, sizeof(taggedName), "%T %s", "ReadyTag", LANG_SERVER, name); - } else { - Format(taggedName, sizeof(taggedName), "%T %s", "NotReadyTag", LANG_SERVER, name); - } - } else { - strcopy(taggedName, sizeof(taggedName), name); - } - - SetConVarStringSafe(teamCvarName, taggedName); - SetConVarStringSafe(flagCvarName, flag); - SetConVarStringSafe(logoCvarName, logo); - SetConVarStringSafe(textCvarName, matchstat); - - if (g_MapsToWin > 1) { - SetConVarIntSafe(scoreCvarName, series_score); - } -} - -stock void SetConVarIntSafe(const char[] name, int value) { - ConVar cvar = FindConVar(name); - if (cvar == null) { - LogError("Failed to find cvar: \"%s\"", name); - } else { - cvar.IntValue = value; - } -} - -stock bool SetConVarStringSafe(const char[] name, const char[] value) { - ConVar cvar = FindConVar(name); - if (cvar == null) { - LogError("Failed to find cvar: \"%s\"", name); - return false; - } else { - cvar.SetString(value); - return true; - } -} - -stock bool GetConVarStringSafe(const char[] name, char[] value, int len) { - ConVar cvar = FindConVar(name); - if (cvar == null) { - LogError("Failed to find cvar: \"%s\"", name); - return false; - } else { - cvar.GetString(value, len); - return true; - } -} - -stock bool OnActiveTeam(int client) { - if (!IsPlayer(client)) - return false; - - int team = GetClientTeam(client); - return team == CS_TEAM_CT || team == CS_TEAM_T; -} - -stock int GetCvarIntSafe(const char[] cvarName) { - ConVar cvar = FindConVar(cvarName); - if (cvar == null) { - LogError("Failed to find cvar \"%s\"", cvar); - return 0; - } else { - return cvar.IntValue; - } -} - -stock void FormatMapName(const char[] mapName, char[] buffer, int len, bool cleanName = false) { - // explode map by '/' so we can remove any directory prefixes (e.g. workshop stuff) - char buffers[4][PLATFORM_MAX_PATH]; - int numSplits = ExplodeString(mapName, "/", buffers, sizeof(buffers), PLATFORM_MAX_PATH); - int mapStringIndex = (numSplits > 0) ? (numSplits - 1) : (0); - strcopy(buffer, len, buffers[mapStringIndex]); - - // do it with backslashes too - numSplits = ExplodeString(buffer, "\\", buffers, sizeof(buffers), PLATFORM_MAX_PATH); - mapStringIndex = (numSplits > 0) ? (numSplits - 1) : (0); - strcopy(buffer, len, buffers[mapStringIndex]); - - if (cleanName) { - if (StrEqual(buffer, "de_cache")) { - strcopy(buffer, len, "Cache"); - } else if (StrEqual(buffer, "de_inferno")) { - strcopy(buffer, len, "Inferno"); - } else if (StrEqual(buffer, "de_dust2")) { - strcopy(buffer, len, "Dust II"); - } else if (StrEqual(buffer, "de_mirage")) { - strcopy(buffer, len, "Mirage"); - } else if (StrEqual(buffer, "de_train")) { - strcopy(buffer, len, "Train"); - } else if (StrEqual(buffer, "de_cbble")) { - strcopy(buffer, len, "Cobblestone"); - } else if (StrEqual(buffer, "de_overpass")) { - strcopy(buffer, len, "Overpass"); - } else if (StrEqual(buffer, "de_nuke")) { - strcopy(buffer, len, "Nuke"); - } - } -} - -stock void GetCleanMapName(char[] buffer, int size) { - char mapName[PLATFORM_MAX_PATH]; - GetCurrentMap(mapName, sizeof(mapName)); - FormatMapName(mapName, buffer, size); -} - -stock GamePhase GetGamePhase() { - return view_as(GameRules_GetProp("m_gamePhase")); -} - -stock bool InHalftimePhase() { - return GetGamePhase() == GamePhase_HalfTime; -} - -stock int AddSubsectionKeysToList(KeyValues kv, const char[] section, ArrayList list, - int maxKeyLength) { - int count = 0; - if (kv.JumpToKey(section)) { - count = AddKeysToList(kv, list, maxKeyLength); - kv.GoBack(); - } - return count; -} - -stock int AddKeysToList(KeyValues kv, ArrayList list, int maxKeyLength) { - int count = 0; - char[] buffer = new char[maxKeyLength]; - if (kv.GotoFirstSubKey(false)) { - do { - count++; - kv.GetSectionName(buffer, maxKeyLength); - list.PushString(buffer); - } while (kv.GotoNextKey(false)); - kv.GoBack(); - } - return count; -} - -stock int AddSubsectionAuthsToList(KeyValues kv, const char[] section, ArrayList list, - int maxKeyLength) { - int count = 0; - if (kv.JumpToKey(section)) { - count = AddAuthsToList(kv, list, maxKeyLength); - kv.GoBack(); - } - return count; -} - -stock int AddAuthsToList(KeyValues kv, ArrayList list, int maxKeyLength) { - int count = 0; - char[] buffer = new char[maxKeyLength]; - char steam64[AUTH_LENGTH]; - char name[MAX_NAME_LENGTH]; - if (kv.GotoFirstSubKey(false)) { - do { - kv.GetSectionName(buffer, maxKeyLength); - kv.GetString(NULL_STRING, name, sizeof(name)); - if (ConvertAuthToSteam64(buffer, steam64)) { - list.PushString(steam64); - Get5_SetPlayerName(steam64, name); - count++; - } - } while (kv.GotoNextKey(false)); - kv.GoBack(); - } - return count; -} - -stock bool RemoveStringFromArray(ArrayList list, const char[] str) { - int index = list.FindString(str); - if (index != -1) { - list.Erase(index); - return true; - } - return false; -} - -stock int OtherCSTeam(int team) { - if (team == CS_TEAM_CT) { - return CS_TEAM_T; - } else if (team == CS_TEAM_T) { - return CS_TEAM_CT; - } else { - return team; - } -} - -stock MatchTeam OtherMatchTeam(MatchTeam team) { - if (team == MatchTeam_Team1) { - return MatchTeam_Team2; - } else if (team == MatchTeam_Team2) { - return MatchTeam_Team1; - } else { - return team; - } -} - -stock bool IsPlayerTeam(MatchTeam team) { - return team == MatchTeam_Team1 || team == MatchTeam_Team2; -} - -public MatchTeam VetoFirstFromString(const char[] str) { - if (StrEqual(str, "team2", false)) { - return MatchTeam_Team2; - } else { - return MatchTeam_Team1; - } -} - -stock bool GetAuth(int client, char[] auth, int size) { - if (client == 0) - return false; - - bool ret = GetClientAuthId(client, AuthId_SteamID64, auth, size); - if (!ret) { - LogError("Failed to get steamid for client %L", client); - } - return ret; -} - -// TODO: might want a auth->client adt-trie to speed this up, maintained during -// client auth and disconnect forwards. -stock int AuthToClient(const char[] auth) { - for (int i = 1; i <= MaxClients; i++) { - if (IsAuthedPlayer(i)) { - char clientAuth[AUTH_LENGTH]; - if (GetAuth(i, clientAuth, sizeof(clientAuth)) && StrEqual(auth, clientAuth)) { - return i; - } - } - } - return -1; -} - -stock int MaxMapsToPlay(int mapsToWin) { - if (g_BO2Match) - return 2; - else - return 2 * mapsToWin - 1; -} - -stock void CSTeamString(int csTeam, char[] buffer, int len) { - if (csTeam == CS_TEAM_CT) { - Format(buffer, len, "CT"); - } else if (csTeam == CS_TEAM_T) { - Format(buffer, len, "T"); - } else { - Format(buffer, len, "none"); - } -} - -stock void GetTeamString(MatchTeam team, char[] buffer, int len) { - if (team == MatchTeam_Team1) { - Format(buffer, len, "team1"); - } else if (team == MatchTeam_Team2) { - Format(buffer, len, "team2"); - } else if (team == MatchTeam_TeamSpec) { - Format(buffer, len, "spec"); - } else { - Format(buffer, len, "none"); - } -} - -stock void GameStateString(Get5State state, char[] buffer, int length) { - switch (state) { - case Get5State_None: - Format(buffer, length, "none"); - case Get5State_PreVeto: - Format(buffer, length, "waiting for map veto"); - case Get5State_Veto: - Format(buffer, length, "map veto"); - case Get5State_Warmup: - Format(buffer, length, "warmup"); - case Get5State_KnifeRound: - Format(buffer, length, "knife round"); - case Get5State_WaitingForKnifeRoundDecision: - Format(buffer, length, "waiting for knife round decision"); - case Get5State_GoingLive: - Format(buffer, length, "going live"); - case Get5State_Live: - Format(buffer, length, "live"); - case Get5State_PostGame: - Format(buffer, length, "postgame"); - } -} - -public MatchSideType MatchSideTypeFromString(const char[] str) { - if (StrEqual(str, "normal", false) || StrEqual(str, "standard", false)) { - return MatchSideType_Standard; - } else if (StrEqual(str, "never_knife", false)) { - return MatchSideType_NeverKnife; - } else { - return MatchSideType_AlwaysKnife; - } -} - -public void MatchSideTypeToString(MatchSideType type, char[] str, int len) { - if (type == MatchSideType_Standard) { - Format(str, len, "standard"); - } else if (type == MatchSideType_NeverKnife) { - Format(str, len, "never_knife"); - } else { - Format(str, len, "always_knife"); - } -} - -stock void ExecCfg(ConVar cvar) { - char cfg[PLATFORM_MAX_PATH]; - cvar.GetString(cfg, sizeof(cfg)); - ServerCommand("exec \"%s\"", cfg); -} - -// Taken from Zephyrus (https://forums.alliedmods.net/showpost.php?p=2231850&postcount=2) -stock bool ConvertSteam2ToSteam64(const char[] steam2Auth, char[] steam64Auth, int size) { - if (strlen(steam2Auth) < 11 || steam2Auth[0] != 'S' || steam2Auth[6] == 'I') { - steam64Auth[0] = 0; - return false; - } - int iUpper = 765611979; - int isteam64Auth = StringToInt(steam2Auth[10]) * 2 + 60265728 + steam2Auth[8] - 48; - int iDiv = isteam64Auth / 100000000; - int iIdx = 9 - (iDiv ? iDiv / 10 + 1 : 0); - iUpper += iDiv; - IntToString(isteam64Auth, steam64Auth[iIdx], size - iIdx); - iIdx = steam64Auth[9]; - IntToString(iUpper, steam64Auth, size); - steam64Auth[9] = iIdx; - return true; -} - -stock bool ConvertSteam3ToSteam2(const char[] steam3Auth, char[] steam2Auth, int size) { - if (StrContains(steam3Auth, "[U:1:") != 0 || strlen(steam3Auth) >= AUTH_LENGTH) { - return false; - } - - // Steam2 -> Steam3 is: - // Old: STEAM_0:A:B - // New: [U:1:B*2+A] - // Example: STEAM_0:1:1234 ---> [U:1:2469] - // - // So the inverse Steam3 -> Steam2 is: - // [U:1:x], x = B * 2 + A - // where A = 1 if x odd, A = 0 if x even - // -> B = (x - A) / 2 - - // Get the x value as a string, then convert it to an int. - char xBuf[AUTH_LENGTH]; - const int startIndex = 5; - int i = startIndex; - for (; i < strlen(steam3Auth) - 1; i++) { - xBuf[i - startIndex] = steam3Auth[i]; - } - xBuf[i - startIndex] = '\0'; - - int x = StringToInt(xBuf); - if (x == 0) { - return false; - } - - int a = (x % 2); - int b = (x - a) / 2; - - Format(steam2Auth, size, "STEAM_0:%d:%d", a, b); - return true; -} - -stock bool ConvertAuthToSteam64(const char[] inputId, char outputId[AUTH_LENGTH], - bool reportErrors = true) { - if (StrContains(inputId, "STEAM_") == 0 && strlen(inputId) >= 11) { // steam2 - return ConvertSteam2ToSteam64(inputId, outputId, sizeof(outputId)); - - } else if (StrContains(inputId, "7656119") == 0) { // steam64 - strcopy(outputId, sizeof(outputId), inputId); - return true; - - } else if (StrContains(inputId, "[U:1:") == 0) { // steam3 - // Convert to steam2 then to steam64. - char steam2[AUTH_LENGTH]; - if (ConvertSteam3ToSteam2(inputId, steam2, sizeof(steam2))) { - return ConvertSteam2ToSteam64(steam2, outputId, sizeof(outputId)); - } - } - - if (reportErrors) { - LogError("Failed to read input auth id \"%s\", inputId", inputId); - } - - return false; -} - -stock bool HelpfulAttack(int attacker, int victim) { - if (!IsValidClient(attacker) || !IsValidClient(victim)) { - return false; - } - int attackerTeam = GetClientTeam(attacker); - int victimTeam = GetClientTeam(victim); - return attackerTeam != victimTeam && attacker != victim; -} - -stock SideChoice SideTypeFromString(const char[] input) { - if (StrEqual(input, "team1_ct", false)) { - return SideChoice_Team1CT; - } else if (StrEqual(input, "team1_t", false)) { - return SideChoice_Team1T; - } else if (StrEqual(input, "team2_ct", false)) { - return SideChoice_Team1T; - } else if (StrEqual(input, "team2_t", false)) { - return SideChoice_Team1CT; - } else if (StrEqual(input, "knife", false)) { - return SideChoice_KnifeRound; - } else { - LogError("Invalid side choice \"%s\", falling back to knife round", input); - return SideChoice_KnifeRound; - } -} - -typedef VoidFunction = function void(); - -stock void DelayFunction(float delay, VoidFunction f) { - DataPack p = CreateDataPack(); - p.WriteFunction(f); - CreateTimer(delay, _DelayFunctionCallback, p); -} - -public Action _DelayFunctionCallback(Handle timer, DataPack data) { - data.Reset(); - Function func = data.ReadFunction(); - Call_StartFunction(INVALID_HANDLE, func); - Call_Finish(); - delete data; -} - -// Deletes a file if it exists. Returns true if the -// file existed AND there was an error deleting it. -public bool DeleteFileIfExists(const char[] path) { - if (FileExists(path)) { - if (!DeleteFile(path)) { - LogError("Failed to delete file %s", path); - return false; - } - } - - return true; -} diff --git a/sourcemod_plugin/get5_apistats/scripting/get5/version.sp b/sourcemod_plugin/get5_apistats/scripting/get5/version.sp deleted file mode 100644 index 73b388a..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/get5/version.sp +++ /dev/null @@ -1,4 +0,0 @@ -#tryinclude "manual_version.sp" -#if !defined PLUGIN_VERSION -#define PLUGIN_VERSION "0.7.1" -#endif diff --git a/sourcemod_plugin/get5_apistats/scripting/get5_apistats.sp b/sourcemod_plugin/get5_apistats/scripting/get5_apistats.sp deleted file mode 100644 index decaefd..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/get5_apistats.sp +++ /dev/null @@ -1,587 +0,0 @@ -/** - * ============================================================================= - * Get5 web API integration - * Copyright (C) 2016. Sean Lewis. All rights reserved. - * ============================================================================= - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "include/get5.inc" -#include "include/logdebug.inc" -#include -#include -#include "get5/util.sp" -#include "get5/version.sp" - -#include -#include // github.com/dordnung/System2/ -#include // github.com/clugg/sm-json -#include "get5/jsonhelpers.sp" - -#pragma semicolon 1 -#pragma newdecls required - -int g_MatchID = -1; - -ConVar g_APIKeyCvar; -char g_APIKey[128]; - -ConVar g_APIURLCvar; -char g_APIURL[128]; - -char g_storedAPIURL[128]; -char g_storedAPIKey[128]; - -ConVar g_FTPHostCvar; -char g_FTPHost[128]; - -ConVar g_FTPUsernameCvar; -char g_FTPUsername[128]; - -ConVar g_FTPPasswordCvar; -char g_FTPPassword[128]; - -ConVar g_FTPPortCvar; -int g_FTPPort; - -ConVar g_FTPEnableCvar; -bool g_FTPEnable; - - -#define LOGO_DIR "resource/flash/econ/tournaments/teams" -#define PANO_DIR "materials/panorama/images/tournaments/teams" -// clang-format off -public Plugin myinfo = { - name = "Get5 Web API Integration", - author = "splewis/phlexplexico", - description = "Records match stats to a get5-web api", - version = "0.4", - url = "https://github.com/phlexplexico/get5-web" -}; -// clang-format on - -public void OnPluginStart() { - InitDebugLog("get5_debug", "get5_api"); - LogDebug("OnPluginStart version=%s", PLUGIN_VERSION); - - g_FTPHostCvar = - CreateConVar("get5_api_ftp_host", "ftp://example.com", "Remote FTP Host. Make sure you do NOT have the trailing slash. Include the path to the directory you wish to have.", FCVAR_PROTECTED); - - g_FTPPortCvar = - CreateConVar("get5_api_ftp_port", "21", "Remote FTP Port", FCVAR_PROTECTED); - - g_FTPUsernameCvar = - CreateConVar("get5_api_ftp_username", "username", "Username for the FTP connection.", FCVAR_PROTECTED); - - g_FTPPasswordCvar = - CreateConVar("get5_api_ftp_password", "supersecret", "Password for the FTP user. Leave blank if no password.", FCVAR_PROTECTED); - - g_FTPEnableCvar = - CreateConVar("get5_api_ftp_enabled", "0", "0 Disables FTP Upload, 1 Enables."); - - g_APIKeyCvar = - CreateConVar("get5_web_api_key", "", "Match API key, this is automatically set through rcon", FCVAR_DONTRECORD); - HookConVarChange(g_APIKeyCvar, ApiInfoChanged); - - g_APIURLCvar = CreateConVar("get5_web_api_url", "", "URL the get5 api is hosted at, IGNORE AS IT IS SYSTEM SET.", FCVAR_DONTRECORD); - - HookConVarChange(g_APIURLCvar, ApiInfoChanged); - - RegConsoleCmd("get5_web_avaliable", - Command_Avaliable); // legacy version since I'm bad at spelling - RegConsoleCmd("get5_web_available", Command_Avaliable); - /** Create and exec plugin's configuration file **/ - AutoExecConfig(true, "get5api"); - -} - -public Action Command_Avaliable(int client, int args) { - char versionString[64] = "unknown"; - ConVar versionCvar = FindConVar("get5_version"); - if (versionCvar != null) { - versionCvar.GetString(versionString, sizeof(versionString)); - } - - JSON_Object json = new JSON_Object(); - - json.SetInt("gamestate", view_as(Get5_GetGameState())); - json.SetInt("avaliable", 1); // legacy version since I'm bad at spelling - json.SetInt("available", 1); - json.SetString("plugin_version", versionString); - - char buffer[128]; - json.Encode(buffer, sizeof(buffer)); - ReplyToCommand(client, buffer); - - delete json; - - return Plugin_Handled; -} - -public void ApiInfoChanged(ConVar convar, const char[] oldValue, const char[] newValue) { - g_APIKeyCvar.GetString(g_APIKey, sizeof(g_APIKey)); - g_APIURLCvar.GetString(g_APIURL, sizeof(g_APIURL)); - - // Add a trailing backslash to the api url if one is missing. - int len = strlen(g_APIURL); - if (len > 0 && g_APIURL[len - 1] != '/') { - StrCat(g_APIURL, sizeof(g_APIURL), "/"); - } - - LogDebug("get5_web_api_url now set to %s", g_APIURL); -} - -static Handle CreateRequest(EHTTPMethod httpMethod, const char[] apiMethod, any:...) { - char url[1024]; - Format(url, sizeof(url), "%s%s", g_APIURL, apiMethod); - - char formattedUrl[1024]; - VFormat(formattedUrl, sizeof(formattedUrl), url, 3); - - LogDebug("Trying to create request to url %s", formattedUrl); - - Handle req = SteamWorks_CreateHTTPRequest(httpMethod, formattedUrl); - if (StrEqual(g_APIKey, "")) { - // Not using a web interface. - return INVALID_HANDLE; - - } else if (req == INVALID_HANDLE) { - LogError("Failed to create request to %s", formattedUrl); - return INVALID_HANDLE; - - } else { - SteamWorks_SetHTTPCallbacks(req, RequestCallback); - AddStringParam(req, "key", g_APIKey); - return req; - } -} - -static Handle CreateDemoRequest(EHTTPMethod httpMethod, const char[] apiMethod, any:...) { - char url[1024]; - Format(url, sizeof(url), "%s%s", g_storedAPIURL, apiMethod); - - char formattedUrl[1024]; - VFormat(formattedUrl, sizeof(formattedUrl), url, 3); - - LogDebug("Trying to create request to url %s", formattedUrl); - - Handle req = SteamWorks_CreateHTTPRequest(httpMethod, formattedUrl); - if (StrEqual(g_storedAPIKey, "")) { - // Not using a web interface. - return INVALID_HANDLE; - - } else if (req == INVALID_HANDLE) { - LogError("Failed to create request to %s", formattedUrl); - return INVALID_HANDLE; - - } else { - SteamWorks_SetHTTPCallbacks(req, RequestCallback); - AddStringParam(req, "key", g_APIKey); - return req; - } -} - -public int RequestCallback(Handle request, bool failure, bool requestSuccessful, - EHTTPStatusCode statusCode) { - if (failure || !requestSuccessful) { - LogError("API request failed, HTTP status code = %d", statusCode); - char response[1024]; - SteamWorks_GetHTTPResponseBodyData(request, response, sizeof(response)); - LogError(response); - return; - } -} - -public void Get5_OnBackupRestore() { - char matchid[64]; - Get5_GetMatchID(matchid, sizeof(matchid)); - g_MatchID = StringToInt(matchid); -} - -public void Get5_OnSeriesInit() { - char matchid[64]; - Get5_GetMatchID(matchid, sizeof(matchid)); - g_MatchID = StringToInt(matchid); - - // Handle new logos. - if (!DirExists(LOGO_DIR)) { - if (!CreateDirectory(LOGO_DIR, 755)) { - LogError("Failed to create logo directory: %s", LOGO_DIR); - } - } - if (!DirExists(PANO_DIR)) { - if (!CreateDirectory(PANO_DIR, 755)) { - LogError("Failed to create logo directory: %s", PANO_DIR); - } - } - - char logo1[32]; - char logo2[32]; - GetConVarStringSafe("mp_teamlogo_1", logo1, sizeof(logo1)); - GetConVarStringSafe("mp_teamlogo_2", logo2, sizeof(logo2)); - CheckForLogo(logo1); - CheckForLogo(logo2); -} - -public void CheckForLogo(const char[] logo) { - if (StrEqual(logo, "")) { - return; - } - - char logoPath[PLATFORM_MAX_PATH + 1]; - char svgLogoPath[PLATFORM_MAX_PATH +1]; - Format(logoPath, sizeof(logoPath), "%s/%s.png", LOGO_DIR, logo); - Format(svgLogoPath, sizeof(svgLogoPath), "%s/%s.svg", PANO_DIR, logo); - - // Try to fetch the file if we don't have it. - if (!FileExists(logoPath)) { - LogDebug("Fetching logo for %s", logo); - Handle req = CreateRequest(k_EHTTPMethodGET, "/static/resource/csgo/resource/flash/econ/tournaments/teams/%s.png", logo); - if (req == INVALID_HANDLE) { - return; - } - - Handle pack = CreateDataPack(); - WritePackString(pack, logo); - - SteamWorks_SetHTTPRequestContextValue(req, view_as(pack)); - SteamWorks_SetHTTPCallbacks(req, LogoCallback); - SteamWorks_SendHTTPRequest(req); - } - - //Attempt to get SVG. - if (!FileExists(svgLogoPath)) { - LogDebug("Fetching logo for %s", logo); - Handle req = CreateRequest(k_EHTTPMethodGET, "/static/resource/csgo/materials/panorama/images/tournaments/teams/%s.svg", logo); - if (req == INVALID_HANDLE) { - return; - } - - Handle svgPack = CreateDataPack(); - WritePackString(svgPack, logo); - - SteamWorks_SetHTTPRequestContextValue(req, view_as(svgPack)); - SteamWorks_SetHTTPCallbacks(req, LogoCallbackSvg); - SteamWorks_SendHTTPRequest(req); - } -} - -public int LogoCallback(Handle request, bool failure, bool successful, EHTTPStatusCode status, int data) { - if (failure || !successful) { - LogError("Logo request failed, status code = %d", status); - return; - } - - DataPack pack = view_as(data); - pack.Reset(); - char logo[32]; - pack.ReadString(logo, sizeof(logo)); - - char logoPath[PLATFORM_MAX_PATH + 1]; - Format(logoPath, sizeof(logoPath), "%s/%s.png", LOGO_DIR, logo); - - LogMessage("Saved logo for %s to %s", logo, logoPath); - SteamWorks_WriteHTTPResponseBodyToFile(request, logoPath); -} - -public int LogoCallbackSvg(Handle request, bool failure, bool successful, EHTTPStatusCode status, int data) { - if (failure || !successful) { - LogError("Logo request failed, status code = %d", status); - return; - } - - DataPack pack = view_as(data); - pack.Reset(); - char logo[32]; - pack.ReadString(logo, sizeof(logo)); - - char svgLogoPath[PLATFORM_MAX_PATH + 1]; - Format(svgLogoPath, sizeof(svgLogoPath), "%s/%s.svg", PANO_DIR, logo); - - LogMessage("Saved logo for %s to %s", logo, svgLogoPath); - SteamWorks_WriteHTTPResponseBodyToFile(request, svgLogoPath); -} - -public void Get5_OnGoingLive(int mapNumber) { - char mapName[64]; - g_FTPEnable = g_FTPEnableCvar.BoolValue; - - GetCurrentMap(mapName, sizeof(mapName)); - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/map/%d/start", g_MatchID, mapNumber); - if (req != INVALID_HANDLE) { - AddStringParam(req, "mapname", mapName); - SteamWorks_SendHTTPRequest(req); - } - // Store Cvar since it gets reset after match finishes? - if (g_FTPEnable) { - Format(g_storedAPIKey, sizeof(g_storedAPIKey), g_APIKey); - Format(g_storedAPIURL, sizeof(g_storedAPIURL), g_APIURL); - } - Get5_AddLiveCvar("get5_web_api_key", g_APIKey); - Get5_AddLiveCvar("get5_web_api_url", g_APIURL); - -} - -public void UpdateRoundStats(int mapNumber) { - int t1score = CS_GetTeamScore(Get5_MatchTeamToCSTeam(MatchTeam_Team1)); - int t2score = CS_GetTeamScore(Get5_MatchTeamToCSTeam(MatchTeam_Team2)); - - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/map/%d/update", g_MatchID, mapNumber); - if (req != INVALID_HANDLE) { - AddIntParam(req, "team1score", t1score); - AddIntParam(req, "team2score", t2score); - SteamWorks_SendHTTPRequest(req); - } - - // Update player stats - KeyValues kv = new KeyValues("Stats"); - Get5_GetMatchStats(kv); - char mapKey[32]; - Format(mapKey, sizeof(mapKey), "map%d", mapNumber); - if (kv.JumpToKey(mapKey)) { - if (kv.JumpToKey("team1")) { - UpdatePlayerStats(kv, MatchTeam_Team1); - kv.GoBack(); - } - if (kv.JumpToKey("team2")) { - UpdatePlayerStats(kv, MatchTeam_Team2); - kv.GoBack(); - } - kv.GoBack(); - } - delete kv; -} - -public void Get5_OnMapResult(const char[] map, MatchTeam mapWinner, int team1Score, int team2Score, - int mapNumber) { - char winnerString[64]; - GetTeamString(mapWinner, winnerString, sizeof(winnerString)); - - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/map/%d/finish", g_MatchID, mapNumber); - if (req != INVALID_HANDLE) { - AddIntParam(req, "team1score", team1Score); - AddIntParam(req, "team2score", team2Score); - AddStringParam(req, "winner", winnerString); - SteamWorks_SendHTTPRequest(req); - } -} - - - -static void AddIntStat(Handle req, KeyValues kv, const char[] field) { - AddIntParam(req, field, kv.GetNum(field)); -} - -public void UpdatePlayerStats(KeyValues kv, MatchTeam team) { - char name[MAX_NAME_LENGTH]; - char auth[AUTH_LENGTH]; - int mapNumber = MapNumber(); - - if (kv.GotoFirstSubKey()) { - do { - kv.GetSectionName(auth, sizeof(auth)); - kv.GetString("name", name, sizeof(name)); - char teamString[16]; - GetTeamString(team, teamString, sizeof(teamString)); - - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/map/%d/player/%s/update", g_MatchID, - mapNumber, auth); - if (req != INVALID_HANDLE) { - AddStringParam(req, "team", teamString); - AddStringParam(req, "name", name); - AddIntStat(req, kv, STAT_KILLS); - AddIntStat(req, kv, STAT_DEATHS); - AddIntStat(req, kv, STAT_ASSISTS); - AddIntStat(req, kv, STAT_FLASHBANG_ASSISTS); - AddIntStat(req, kv, STAT_TEAMKILLS); - AddIntStat(req, kv, STAT_SUICIDES); - AddIntStat(req, kv, STAT_DAMAGE); - AddIntStat(req, kv, STAT_HEADSHOT_KILLS); - AddIntStat(req, kv, STAT_ROUNDSPLAYED); - AddIntStat(req, kv, STAT_BOMBPLANTS); - AddIntStat(req, kv, STAT_BOMBDEFUSES); - AddIntStat(req, kv, STAT_1K); - AddIntStat(req, kv, STAT_2K); - AddIntStat(req, kv, STAT_3K); - AddIntStat(req, kv, STAT_4K); - AddIntStat(req, kv, STAT_5K); - AddIntStat(req, kv, STAT_V1); - AddIntStat(req, kv, STAT_V2); - AddIntStat(req, kv, STAT_V3); - AddIntStat(req, kv, STAT_V4); - AddIntStat(req, kv, STAT_V5); - AddIntStat(req, kv, STAT_FIRSTKILL_T); - AddIntStat(req, kv, STAT_FIRSTKILL_CT); - AddIntStat(req, kv, STAT_FIRSTDEATH_T); - AddIntStat(req, kv, STAT_FIRSTDEATH_CT); - AddIntStat(req, kv, STAT_TRADEKILL); - SteamWorks_SendHTTPRequest(req); - } - - } while (kv.GotoNextKey()); - kv.GoBack(); - } -} - -static void AddStringParam(Handle request, const char[] key, const char[] value) { - if (!SteamWorks_SetHTTPRequestGetOrPostParameter(request, key, value)) { - LogError("Failed to add http param %s=%s", key, value); - } else { - LogDebug("Added param %s=%s to request", key, value); - } -} - -static void AddIntParam(Handle request, const char[] key, int value) { - char buffer[32]; - IntToString(value, buffer, sizeof(buffer)); - AddStringParam(request, key, buffer); -} - -public void Get5_OnMapVetoed(MatchTeam team, const char[] map){ - char teamString[64]; - GetTeamString(team, teamString, sizeof(teamString)); - LogDebug("Map Veto START team %s map vetoed %s", team, map); - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/vetoUpdate", g_MatchID); - if (req != INVALID_HANDLE) { - AddStringParam(req, "map", map); - AddStringParam(req, "teamString", teamString); - AddStringParam(req, "pick_or_veto", "ban"); - SteamWorks_SendHTTPRequest(req); - } - LogDebug("Accepted Map Veto."); -} - -public void Get5_OnDemoFinished(const char[] filename){ - g_FTPEnable = g_FTPEnableCvar.BoolValue; - if (g_FTPEnable) { - LogDebug("About to enter UploadDemo."); - int mapNumber = MapNumber(); - char zippedFile[PLATFORM_MAX_PATH]; - char formattedURL[PLATFORM_MAX_PATH]; - UploadDemo(filename, zippedFile); - - Handle req = CreateDemoRequest(k_EHTTPMethodPOST, "match/%d/map/%d/demo", g_MatchID, mapNumber-1); - LogDebug("Our api url: %s", g_storedAPIURL); - // Send URL to store in database to show users at end of match. - // This requires anonmyous downloads on the FTP server unless - // you give out usernames. - if (req != INVALID_HANDLE) { - Format(formattedURL, sizeof(formattedURL), "%sstatic/demos/%s", g_storedAPIURL, zippedFile); - LogDebug("Our URL: %s", formattedURL); - AddStringParam(req, "demoFile", formattedURL); - SteamWorks_SendHTTPRequest(req); - } - // Need to store as get5 recycles the configs before the demos finish recording. - Format(g_storedAPIKey, sizeof(g_storedAPIKey), ""); - Format(g_storedAPIURL, sizeof(g_storedAPIURL), ""); - } -} - -public void UploadDemo(const char[] filename, char zippedFile[PLATFORM_MAX_PATH]){ - char remoteDemoPath[PLATFORM_MAX_PATH]; - if(filename[0]){ - g_FTPHostCvar.GetString(g_FTPHost, sizeof(g_FTPHost)); - g_FTPPort = g_FTPPortCvar.IntValue; - g_FTPUsernameCvar.GetString(g_FTPUsername, sizeof(g_FTPUsername)); - g_FTPPasswordCvar.GetString(g_FTPPassword, sizeof(g_FTPPassword)); - - Format(zippedFile, sizeof(zippedFile), "%s", filename); - Format(remoteDemoPath, sizeof(remoteDemoPath), "%s/%s", g_FTPHost, zippedFile); - LogDebug("Our File is: %s and remote demo path of %s", zippedFile, remoteDemoPath); - System2FTPRequest ftpRequest = new System2FTPRequest(FtpResponseCallback, remoteDemoPath); - ftpRequest.AppendToFile = false; - ftpRequest.CreateMissingDirs = true; - ftpRequest.SetAuthentication(g_FTPUsername, g_FTPPassword); - ftpRequest.SetPort(g_FTPPort); - ftpRequest.SetProgressCallback(FtpProgressCallback); - LogDebug("Our File is: %s", zippedFile); - - ftpRequest.SetInputFile(zippedFile); - ftpRequest.StartRequest(); - } else{ - LogDebug("FTP Uploads Disabled OR Filename was empty (no demo to upload). Change config to enable."); - } -} - - -public void FtpProgressCallback(System2FTPRequest request, int dlTotal, int dlNow, int ulTotal, int ulNow) { - char file[PLATFORM_MAX_PATH]; - request.GetInputFile(file, sizeof(file)); - if (strlen(file) > 0) { - LogDebug("Uploading %s file with %d bytes total, %d now", file, ulTotal, ulNow); - } -} - -public void FtpResponseCallback(bool success, const char[] error, System2FTPRequest request, System2FTPResponse response) { - if (success || StrContains(error, "Uploaded unaligned file size") > -1) { - char file[PLATFORM_MAX_PATH]; - request.GetInputFile(file, sizeof(file)); - if (strlen(file) > 0) { - if (DeleteFileIfExists(file)) { - LogDebug("Deleted file after complete."); - } - } - } else{ - LogError("There was a problem: %s", error); - } -} - -public void Get5_OnMapPicked(MatchTeam team, const char[] map){ - char teamString[64]; - GetTeamString(team, teamString, sizeof(teamString)); - LogDebug("Map Pick START team %s map picked %s", team, map); - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/vetoUpdate", g_MatchID); - if (req != INVALID_HANDLE) { - AddStringParam(req, "map", map); - AddStringParam(req, "teamString", teamString); - AddStringParam(req, "pick_or_veto", "pick"); - SteamWorks_SendHTTPRequest(req); - } - LogDebug("Accepted Map Pick."); -} - -public void Get5_OnSeriesResult(MatchTeam seriesWinner, int team1MapScore, int team2MapScore) { - char winnerString[64]; - GetTeamString(seriesWinner, winnerString, sizeof(winnerString)); - - KeyValues kv = new KeyValues("Stats"); - Get5_GetMatchStats(kv); - bool forfeit = kv.GetNum(STAT_SERIES_FORFEIT, 0) != 0; - delete kv; - - Handle req = CreateRequest(k_EHTTPMethodPOST, "match/%d/finish", g_MatchID); - if (req != INVALID_HANDLE) { - AddStringParam(req, "winner", winnerString); - AddIntParam(req, "forfeit", forfeit); - SteamWorks_SendHTTPRequest(req); - } - - g_APIKeyCvar.SetString(""); -} - -public void Get5_OnRoundStatsUpdated() { - if (Get5_GetGameState() == Get5State_Live) { - UpdateRoundStats(MapNumber()); - } -} - -static int MapNumber() { - int t1, t2, n; - int buf; - Get5_GetTeamScores(MatchTeam_Team1, t1, buf); - Get5_GetTeamScores(MatchTeam_Team2, t2, buf); - Get5_GetTeamScores(MatchTeam_TeamNone, n, buf); - return t1 + t2 + n; -} diff --git a/sourcemod_plugin/get5_apistats/scripting/include/get5.inc b/sourcemod_plugin/get5_apistats/scripting/include/get5.inc deleted file mode 100644 index 422e7cf..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/include/get5.inc +++ /dev/null @@ -1,225 +0,0 @@ -#if defined _get5_included_ -#endinput -#endif -#define _get5_included_ - -enum Get5State { - Get5State_None, // no setup has taken place - Get5State_PreVeto, // warmup, waiting for the veto - Get5State_Veto, // warmup, doing the veto - Get5State_Warmup, // setup done, waiting for players to ready up - Get5State_KnifeRound, // in the knife round - Get5State_WaitingForKnifeRoundDecision, // waiting for a .stay/.swap command after the knife - Get5State_GoingLive, // in the lo3 process - Get5State_Live, // the match is live - Get5State_PostGame, // postgame screen + waiting for GOTV to finish broadcast -}; - -enum MatchTeam { - MatchTeam_Team1, - MatchTeam_Team2, - MatchTeam_TeamSpec, - MatchTeam_TeamNone, - MatchTeam_Count, -}; - -enum MatchSideType { - MatchSideType_Standard, // Team that doesn't pick map gets side choice, leftovers go to knife - // rounds - MatchSideType_AlwaysKnife, // All maps use a knife round to pick sides - MatchSideType_NeverKnife, // Team 1 always starts CT -}; - -enum SideChoice { - SideChoice_Team1CT, // Team 1 will start on CT - SideChoice_Team1T, // Team 2 will start on T - SideChoice_KnifeRound, // There will be a knife round to choose sides -}; - -// Called each get5-event with JSON formatted event text. -forward void Get5_OnEvent(const char[] eventJson); - -// Called when a series is first setup. -// Note: do not rely on the state of any cvars at this point. -forward void Get5_OnSeriesInit(); - -// Called each time in a match when a map is going live. -// The mapNumber parameter starts at 0. -forward void Get5_OnGoingLive(int mapNumber); - -// Called whenever the gamestate phase is changed. -forward void Get5_OnGameStateChanged(Get5State oldState, Get5State newState); - -// Called when the stats for the last round have been updated. -forward void Get5_OnRoundStatsUpdated(); - -// Called at the end of a map in a series. -forward void Get5_OnMapResult(const char[] map, MatchTeam mapWinner, int team1Score, int team2Score, - int mapNumber); - -// Called at the end of a full match. -// Note: both Get5_OnMapResult and Get5_OnSeriesResult are called on the last map of a series. -forward void Get5_OnSeriesResult(MatchTeam seriesWinner, int team1MapScore, int team2MapScore); - -forward void Get5_OnPreLoadMatchConfig(const char[] filePath); - -// Called when a match config fails to load. -forward void Get5_OnLoadMatchConfigFailed(const char[] reason); - -// Called when a team vetoes a map. -forward void Get5_OnMapVetoed(MatchTeam team, const char[] map); - -// Called when a team selects a map. -// The team parameter will be MatchTeam_TeamNone if the map was selected as the last remaining map -// and not by one of the teams specifically. -forward void Get5_OnMapPicked(MatchTeam team, const char[] map); - -// Called when a team selects a side. -forward void Get5_OnSidePicked(MatchTeam team, const char[] map, int side); - -// Called when a demo finishes recording. -forward void Get5_OnDemoFinished(const char[] filename); - -// Called when a match backup is restored. -forward void Get5_OnBackupRestore(); - -// Returns the current pug gamestate. -native Get5State Get5_GetGameState(); - -// Prints a plugin-formatted message to a client. -native void Get5_Message(int client, const char[] format, any:...); - -// Prints a plugin-formatted message to a team. -native void Get5_MessageToTeam(MatchTeam team, const char[] format, any:...); - -// Prints a plugin-formatted message to all clients. -native void Get5_MessageToAll(const char[] format, any:...); - -// Loads a match config (keyvalues or JSON) from a local file. -// Returns true if the config was successfully loaded. -native bool Get5_LoadMatchConfig(const char[] filename); - -// Loads a match config by downloading a remote config via a HTTP GET request. -// Request parameters should be left out of the url and put into the optional ArrayLists parameters. -native bool Get5_LoadMatchConfigFromURL(const char[] url, ArrayList paramNames = null, - ArrayList paramValues = null); - -// Adds a player to a match team. You can optionally force set a player name here as well. -// Returns if they were successfully added. -native bool Get5_AddPlayerToTeam(const char[] steamId, MatchTeam team, - const char[] playerName = ""); - -// Force sets a steam64 to map to a specified playername -native bool Get5_SetPlayerName(const char[] steamId, const char[] playerName); - -// Removes a player from all match teams. -// Returns if they were successfully removed (false if not round). -native bool Get5_RemovePlayerFromTeam(const char[] steamId); - -// Returns the current match team a auth is mapped to. -native MatchTeam Get5_GetPlayerTeam(const char[] steamId); - -// Translates a CS team (CS_TEAM_T, etc.) to a Match team. -native MatchTeam Get5_CSTeamToMatchTeam(int csTeam); - -// Translate da MatchTeam to a CS team. -native int Get5_MatchTeamToCSTeam(MatchTeam team); - -// Gets the scores for a match team. -native void Get5_GetTeamScores(MatchTeam team, int& seriesScore, int& currentMapScore); - -// Gets the current matchid. -native void Get5_GetMatchID(char[] id, int length); - -// Sets the current matchid. -native void Get5_SetMatchID(const char[] id); - -// Adds a cvar to be set when going live. If the cvar is already in the cvars for the match, the new -// value will replace the old value if the override parameter is true. -// Note: this should only be used when a match config loaded. -native void Get5_AddLiveCvar(const char[] name, const char[] value, bool override = true); - -// Copies the current series stats into the passed KeyValues structure. -// Below are the keys used for stats in the kv copied. -// The caller is responsible for creating and deleting a KeyValues -// object if using this method. -native bool Get5_GetMatchStats(KeyValues kv); - -// Increases an (integer-typed) player statistic in the plugin's stats keyvalue structure. -native int Get5_IncreasePlayerStat(int client, const char[] statName, int amount = 1); - -// Series stats (root section) -#define STAT_SERIESWINNER "winner" -#define STAT_SERIESTYPE "series_type" -#define STAT_SERIES_TEAM1NAME "team1_name" -#define STAT_SERIES_TEAM2NAME "team2_name" -#define STAT_SERIES_FORFEIT "forfeit" - -// Map stats (under "map0", "map1", etc.) -#define STAT_MAPNAME "mapname" -#define STAT_MAPWINNER "winner" -#define STAT_DEMOFILENAME "demo_filename" - -// Team stats (under map section, then "team1" or "team2") -#define STAT_TEAMSCORE "score" - -// Player stats (under map section, then team section, then player's steam64) -#define STAT_NAME "name" -#define STAT_KILLS "kills" -#define STAT_DEATHS "deaths" -#define STAT_ASSISTS "assists" -#define STAT_FLASHBANG_ASSISTS "flashbang_assists" -#define STAT_TEAMKILLS "teamkills" -#define STAT_SUICIDES "suicides" -#define STAT_DAMAGE "damage" -#define STAT_HEADSHOT_KILLS "headshot_kills" -#define STAT_ROUNDSPLAYED "roundsplayed" -#define STAT_BOMBDEFUSES "bomb_defuses" -#define STAT_BOMBPLANTS "bomb_plants" -#define STAT_1K "1kill_rounds" -#define STAT_2K "2kill_rounds" -#define STAT_3K "3kill_rounds" -#define STAT_4K "4kill_rounds" -#define STAT_5K "5kill_rounds" -#define STAT_V1 "v1" -#define STAT_V2 "v2" -#define STAT_V3 "v3" -#define STAT_V4 "v4" -#define STAT_V5 "v5" -#define STAT_FIRSTKILL_T "firstkill_t" -#define STAT_FIRSTKILL_CT "firstkill_ct" -#define STAT_FIRSTDEATH_T "firstdeath_t" -#define STAT_FIRSTDEATH_CT "firstdeath_ct" -#define STAT_TRADEKILL "tradekill" - -public SharedPlugin __pl_get5 = { - name = "get5", file = "get5.smx", -#if defined REQUIRE_PLUGIN - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_PLUGIN -public __pl_get5_SetNTVOptional() { - MarkNativeAsOptional("Get5_GetGameState"); - MarkNativeAsOptional("Get5_Message"); - MarkNativeAsOptional("Get5_MessageToTeam"); - MarkNativeAsOptional("Get5_MessageToAll"); - MarkNativeAsOptional("Get5_LoadMatchConfig"); - MarkNativeAsOptional("Get5_LoadMatchConfigFromURL"); - MarkNativeAsOptional("Get5_AddPlayerToTeam"); - MarkNativeAsOptional("Get5_SetPlayerName"); - MarkNativeAsOptional("Get5_RemovePlayerFromTeam"); - MarkNativeAsOptional("Get5_GetPlayerTeam"); - MarkNativeAsOptional("Get5_CSTeamToMatchTeam"); - MarkNativeAsOptional("Get5_MatchTeamToCSTeam"); - MarkNativeAsOptional("Get5_GetTeamScores"); - MarkNativeAsOptional("Get5_GetMatchID"); - MarkNativeAsOptional("Get5_SetMatchID"); - MarkNativeAsOptional("Get5_AddLiveCvar"); - MarkNativeAsOptional("Get5_IncreasePlayerStat"); - MarkNativeAsOptional("Get5_GetMatchStats"); -} -#endif diff --git a/sourcemod_plugin/get5_apistats/scripting/include/logdebug.inc b/sourcemod_plugin/get5_apistats/scripting/include/logdebug.inc deleted file mode 100644 index c333f05..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/include/logdebug.inc +++ /dev/null @@ -1,154 +0,0 @@ -/* - * logdebug.inc by Dr. McKay - * - * A simple to use library for debug logging which can be redirected or disabled on-the-fly. - * Employs transitional syntax - SourceMod 1.7 or newer is required to compile and run. - */ - -#if defined _logdebug_included -#endinput -#endif -#define _logdebug_included - -// define NO_DEBUG before including this file to completely disable all debugging -#if defined NO_DEBUG -stock void InitDebugLog(const char[] convarName, const char[] debugTag, - int adminFlags = ADMFLAG_GENERIC) {} -stock bool LogDebug(const char[] format, any...) { - return false; -} -#endinput -#endif - -#define DEBUG_SERVER_CONSOLE 1 /**< Message will be routed to server console */ -#define DEBUG_CLIENT_CONSOLE 2 /**< Message will be routed to all clients' consoles */ -#define DEBUG_ADMIN_CONSOLE \ - 4 /**< Message will be routed to consoles of admins with a flag specified by plugin */ -#define DEBUG_CLIENT_CHAT \ - 8 /**< Message will be routed to all clients' chat boxes (and consequently consoles) */ -#define DEBUG_ADMIN_CHAT \ - 16 /**< Message will be routed to chat boxes of admins with a flag specified by plugin */ -#define DEBUG_LOG_FILE 32 /**< Message will be routed to plugin's debug log */ - -ConVar g_cvarDebugMode; -char g_DebugLogFileName[PLATFORM_MAX_PATH]; -char g_DebugTag[11]; -char g_DebugCvarName[64]; -int g_DebugAdminFlags; - -/** - * Inits debug logging. You must call this in OnPluginStart(). - * - * @param convarName A name to use for the cvar which controls debug log output. Also - * used - * as filename for logfile. - * @param debugTag Tag to prepend to messages, without []. Max 10 characters. - * @param adminFlag One or more admin flagbits which define whether a user is an - * "admin". If you pass multiple flags, users will need ALL flags. - * @noreturn - */ -stock void InitDebugLog(const char[] convarName, const char[] debugTag, - int adminFlags = ADMFLAG_GENERIC) { - BuildPath(Path_SM, g_DebugLogFileName, sizeof(g_DebugLogFileName), "logs/%s.log", convarName); - - char flagChars[32]; - AdminFlag flags[22]; - int numFlags = FlagBitsToArray(adminFlags, flags, sizeof(flags)); - for (int i = 0; i < numFlags; i++) { - int len = strlen(flagChars); - - if (len > 0) { - len += StrCat(flagChars, sizeof(flagChars), ", "); - } - - int flag = 0; - FindFlagChar(flags[i], flag); - flagChars[len] = view_as(flag); - - flagChars[len + 1] = '\0'; - } - - g_DebugAdminFlags = adminFlags; - - char convarDescription[512]; - Format( - convarDescription, sizeof(convarDescription), - "Add up values to enable debug logging to those locations\n 1 = server console\n 2 = all clients' consoles\n 4 = consoles of admins with '%s' flag%s or access to '%s' override\n 8 = all clients' chat\n 16 = chat of admins with '%s' flag%s or access to '%s' override\n 32 = debug log file %s", - flagChars, flagChars[1] == '\0' ? "" : "s", convarName, flagChars, - flagChars[1] == '\0' ? "" : "s", convarName, g_DebugLogFileName); - g_cvarDebugMode = - CreateConVar(convarName, "0", convarDescription, FCVAR_DONTRECORD, true, 0.0, true, 63.0); - - strcopy(g_DebugTag, sizeof(g_DebugTag), debugTag); - strcopy(g_DebugCvarName, sizeof(g_DebugCvarName), convarName); -} - -/** - * Logs a message to all enabled debug output points - * - * @param format Message text with formatting tokens - * @param ... Variable number of format parameters - * @return true if message was output to at least one place - */ -stock bool LogDebug(const char[] format, any...) { - if (g_cvarDebugMode == null) { - ThrowError("InitDebugLog must be called before LogDebug"); - } - - int output = g_cvarDebugMode.IntValue; - if (output == 0) { - return false; - } - - char buffer[512]; - VFormat(buffer, sizeof(buffer), format, 2); - - if (output & DEBUG_SERVER_CONSOLE) { - PrintToServer("[%s] %s", g_DebugTag, buffer); - } - - if (output & DEBUG_CLIENT_CONSOLE) { - for (int i = 1; i <= MaxClients; i++) { - if (IsClientInGame(i) && !IsFakeClient(i)) { - PrintToConsole(i, "[%s] %s", g_DebugTag, buffer); - } - } - } - - if (output & DEBUG_ADMIN_CONSOLE) { - for (int i = 1; i <= MaxClients; i++) { - if (IsClientInGame(i) && !IsFakeClient(i) && - CheckCommandAccess(i, g_DebugCvarName, g_DebugAdminFlags, true)) { - PrintToConsole(i, "[%s] %s", g_DebugTag, buffer); - } - } - } - - if (output & DEBUG_CLIENT_CHAT) { - PrintToChatAll("[%s] %s", g_DebugTag, buffer); - } - - if (output & DEBUG_ADMIN_CHAT) { - for (int i = 1; i <= MaxClients; i++) { - if (IsClientInGame(i) && !IsFakeClient(i) && - CheckCommandAccess(i, g_DebugCvarName, g_DebugAdminFlags, true)) { - PrintToChat(i, "[%s] %s", g_DebugTag, buffer); - } - } - } - - if (output & DEBUG_LOG_FILE) { - LogToFileEx(g_DebugLogFileName, "[%s] %s", g_DebugTag, buffer); - } - - return true; -} - -/** - * Returns a bitstring containing bits enabled for each output location (see DEBUG_ constants) - * - * @return bitstring for enabled outputs - */ -stock int GetDebugOutputs() { - return g_cvarDebugMode.IntValue; -} diff --git a/sourcemod_plugin/get5_apistats/scripting/include/restorecvars.inc b/sourcemod_plugin/get5_apistats/scripting/include/restorecvars.inc deleted file mode 100644 index ae3e16e..0000000 --- a/sourcemod_plugin/get5_apistats/scripting/include/restorecvars.inc +++ /dev/null @@ -1,113 +0,0 @@ -#define CVAR_NAME_MAX_LENGTH 128 -#define CVAR_VALUE_MAX_LENGTH 128 - -// Returns a cvar Handle that can be used to restore cvars. -stock Handle SaveCvars(ArrayList cvarNames) { - ArrayList storageList = CreateArray(); - ArrayList cvarNameList = new ArrayList(CVAR_NAME_MAX_LENGTH); - ArrayList cvarValueList = new ArrayList(CVAR_VALUE_MAX_LENGTH); - - char nameBuffer[CVAR_NAME_MAX_LENGTH]; - char valueBuffer[CVAR_VALUE_MAX_LENGTH]; - for (int i = 0; cvarNames != null && i < cvarNames.Length; i++) { - cvarNames.GetString(i, nameBuffer, sizeof(nameBuffer)); - - Handle cvar = FindConVar(nameBuffer); - if (cvar != INVALID_HANDLE) { - GetConVarString(cvar, valueBuffer, sizeof(valueBuffer)); - cvarNameList.PushString(nameBuffer); - cvarValueList.PushString(valueBuffer); - } - } - - storageList.Push(cvarNameList); - storageList.Push(cvarValueList); - return storageList; -} - -// Restores cvars to their previous value using a return value of SaveCvars. -stock void RestoreCvars(Handle& cvarStorage, bool close = true) { - ArrayList cvarNameList = view_as(GetArrayCell(cvarStorage, 0)); - ArrayList cvarValueList = view_as(GetArrayCell(cvarStorage, 1)); - - char name[CVAR_NAME_MAX_LENGTH]; - char value[CVAR_VALUE_MAX_LENGTH]; - for (int i = 0; i < cvarNameList.Length; i++) { - cvarNameList.GetString(i, name, sizeof(name)); - cvarValueList.GetString(i, value, sizeof(value)); - - Handle cvar = FindConVar(name); - if (cvar != INVALID_HANDLE) { - SetConVarString(cvar, value); - } - } - - if (close) { - CloseCvarStorage(cvarStorage); - } -} - -// Closes a cvar storage object returned by SaveCvars. -stock void CloseCvarStorage(Handle& cvarStorage) { - if (cvarStorage == INVALID_HANDLE) { - return; - } - - CloseHandle(GetArrayCell(cvarStorage, 0)); - CloseHandle(GetArrayCell(cvarStorage, 1)); - CloseHandle(cvarStorage); - cvarStorage = INVALID_HANDLE; -} - -// Returns the first "word" in a line, as seperated by whitespace. -stock bool __firstWord(const char[] line, char[] buffer, int len) { - char[] lineBuffer = new char[strlen(line)]; - strcopy(lineBuffer, strlen(line), line); - TrimString(lineBuffer); - int splitIndex = StrContains(line, " "); - if (splitIndex == -1) - splitIndex = StrContains(line, "\t"); - - if (splitIndex == -1) { - Format(buffer, len, ""); - return false; - } - - int destLen = splitIndex + 1; - if (destLen > len) - destLen = len; - - strcopy(buffer, destLen, lineBuffer); - return true; -} - -// Wrapper for SetCvars from an arbitrary file. -// Returns if successful. -stock Handle ExecuteAndSaveCvars(const char[] cfgFile) { - char lineBuffer[CVAR_NAME_MAX_LENGTH + CVAR_VALUE_MAX_LENGTH]; - char nameBuffer[CVAR_NAME_MAX_LENGTH]; - - char filePath[PLATFORM_MAX_PATH]; - Format(filePath, sizeof(filePath), "cfg/%s", cfgFile); - - File file = OpenFile(filePath, "r"); - if (file != null) { - ArrayList nameList = new ArrayList(CVAR_NAME_MAX_LENGTH); - - while (!file.EndOfFile() && file.ReadLine(lineBuffer, sizeof(lineBuffer))) { - if (__firstWord(lineBuffer, nameBuffer, sizeof(nameBuffer))) { - TrimString(nameBuffer); - nameList.PushString(nameBuffer); - } - } - - Handle ret = SaveCvars(nameList); - ServerCommand("exec %s", cfgFile); - delete nameList; - delete file; - return ret; - } else { - LogError("Failed to open file for reading: %s", filePath); - return INVALID_HANDLE; - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/chi/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/chi/get5.phrases.txt deleted file mode 100644 index 56571b7..0000000 --- a/sourcemod_plugin/get5_apistats/translations/chi/get5.phrases.txt +++ /dev/null @@ -1,327 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "chi" "当您的队伍准备好进行Veto(Ban图)时,请输入{GREEN}!ready{NORMAL}。" - } - "WaitingForCastersReadyInfoMessage" - { - "chi" "正在等待裁判输入{GREEN}!ready{NORMAL}来开始比赛。" - } - "ReadyToRestoreBackupInfoMessage" - { - "chi" "当您准备好恢复比赛至备份档案时,请输入{GREEN}!ready{NORMAL}。" - } - "ReadyToKnifeInfoMessage" - { - "chi" "当您准备好进行刀局时,请输入{GREEN}!ready{NORMAL}。" - } - "ReadyToStartInfoMessage" - { - "chi" "当您准备好开始比赛时,请输入{GREEN}!ready{NORMAL}。" - } - "YouAreReady" - { - "chi" "您已被标记为准备就绪。" - } - "YouAreNotReady" - { - "chi" "您已被标记为未准备好。" - } - "WaitingForEnemySwapInfoMessage" - { - "chi" "{1}赢得刀局。等待他们输入!stay或是!swapwon来选择留下还是交换队伍。" - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "chi" "当GOTV播放结束时,地图将被切换。" - } - "NoMatchSetupInfoMessage" - { - "chi" "没有设置比赛配置" - } - "YourAreNotAPlayerInfoMessage" - { - "chi" "您并不是这场比赛的玩家" - } - "TeamIsFullInfoMessage" - { - "chi" "您的团队已满" - } - "TeamForfeitInfoMessage" - { - "chi" "{1}未及时准备就绪,已被视为弃权。" - } - "MinutesToForfeitMessage" - { - "chi" "{1}有{2}分的时间来准备就绪,否则将被视为放弃比赛。" - } - "SecondsToForfeitInfoMessage" - { - "chi" "{1}有{2}秒的时间来准备就绪,否则将被视为放弃比赛。" - } - "10SecondsToForfeitInfoMessage" - { - "chi" "{1}有10秒的时间来准备就绪,否则将被视为放弃比赛。" - } - "PausePeriodSuffix" - { - "chi" "于这个半场" - } - "MaxPausesUsedInfoMessage" - { - "chi" "您的队伍已经使用了最大为{1}次的暂停次数{2}。" - } - "MaxPausesTimeUsedInfoMessage" - { - "chi" "您的队伍已经使用了最大为{1}秒的暂停时间{2}。" - } - "MatchPausedByTeamMessage" - { - "chi" "{1}暂停了比赛。" - } - "MatchTechPausedByTeamMessage" - { - "chi" "{1}要求发起一个技术暂停。" - } - "AdminForceTechPauseInfoMessage" - { - "chi" "一位管理员发起了技术暂停。" - } - "PauseTimeExpiration10SecInfoMessage" - { - "chi" "{1}的暂停时间即将耗尽,将在10秒后解除暂停。" - } - "PauseTimeExpirationInfoMessage" - { - "chi" "{1}剩余{2}秒的暂停时间{3}。" - } - "PauseRunoutInfoMessage" - { - "chi" "{1}的暂停时间已经耗尽,已解除比赛的暂停。" - } - "MatchUnpauseInfoMessage" - { - "chi" "{1:N}解除了比赛的暂停。" - } - "WaitingForUnpauseInfoMessage" - { - "chi" "{1}想要取消暂停,正在等待{2}输入!unpause来取消暂停。" - } - "PausesLeftInfoMessage" - { - "chi" "{1}剩余{2}次pauses暂停次数{3}。" - } - "OnePauseLeftInfoMessage" - { - "chi" "{1}剩余{2}次pauses暂停次数{3}。" - } - "TeamFailToReadyMinPlayerCheck" - { - "chi" "服务器上至少有{1}名玩家,您才能准备就绪。" - } - "TeamReadyToVetoInfoMessage" - { - "chi" "{1}已准备好进行Veto(Ban图)。" - } - "TeamReadyToRestoreBackupInfoMessage" - { - "chi" "{1}已准备好恢复比赛至备份档案。" - } - "TeamReadyToKnifeInfoMessage" - { - "chi" "{1}已准备好拼刀选边。" - } - "TeamReadyToBeginInfoMessage" - { - "chi" "{1}已准备好开始比赛。" - } - "TeamNotReadyInfoMessage" - { - "chi" "{1}已不在准备就绪状态。" - } - "ForceReadyInfoMessage" - { - "chi" "如果您有不到{1}名玩家,您可以输入{GREEN}!forceready{NORMAL}来强制准备您的队伍。" - } - "TeammateForceReadied" - { - "chi" "您的队伍已被{GREEN}{1}{NORMAL}强制准备就绪。" - } - "AdminForceReadyInfoMessage" - { - "chi" "一名管理员强制准备了所有队伍。" - } - "AdminForceEndInfoMessage" - { - "chi" "一名管理员强制结束了比赛。" - } - "AdminForcePauseInfoMessage" - { - "chi" "一名管理员强制暂停了比赛。" - } - "AdminForceUnPauseInfoMessage" - { - "chi" "一名管理员强制解除了比赛暂停。" - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "chi" "{1}想停止比赛并重新加载比赛至上一回合,需要{2}输入!stop来确认。" - } - "TeamWinningSeriesInfoMessage" - { - "chi" "{1}{NORMAL}在这系列比赛中正处于领先状态 {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "chi" "此系列比赛终结于{1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "chi" "下一张地图在此系列比赛中是{GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "chi" "{1}赢得了这局比赛。" - } - "TeamTiedMatchInfoMessage" - { - "chi" "{1}与{2}打成了平局。" - } - "TeamsSplitSeriesBO2InfoMessage" - { - "chi" "{1}和{2}在此系列比赛中平局 1-1。" - } - "TeamWonSeriesInfoMessage" - { - "chi" "{1}赢得了此系列比赛 {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "chi" "这场比赛已完结。" - } - "CurrentScoreInfoMessage" - { - "chi" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "chi" "成功加载备份档案 {1}" - } - "MatchBeginInSecondsInfoMessage" - { - "chi" "这场比赛将于{1}后开始。" - } - "MatchIsLiveInfoMessage" - { - "chi" "比赛已{GREEN}开始" - } - "KnifeIn5SecInfoMessage" - { - "chi" "刀局将在5秒后开始。" - } - "KnifeInfoMessage" - { - "chi" "刀局!" - } - "TeamDecidedToStayInfoMessage" - { - "chi" "{1}已决定留下。" - } - "TeamDecidedToSwapInfoMessage" - { - "chi" "{1}已决定交换。" - } - "TeamLostTimeToDecideInfoMessage" - { - "chi" "{1}将会留下来,因为他们没有及时做出决定。" - } - "ChangingMapInfoMessage" - { - "chi" "切换地图至{GREEN}{1}......" - } - "MapDecidedInfoMessage" - { - "chi" "地图已被确定:" - } - "MapIsInfoMessage" - { - "chi" "地图 {1}: {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "chi" "{1}挑选了{GREEN}{2}{NORMAL}作为地图 {3}" - } - "TeamSelectSideInfoMessage" - { - "chi" "{1}已选择在{GREEN}{2}{NORMAL}开始 {3}" - } - "TeamVetoedMapInfoMessage" - { - "chi" "{1}vetoed(Ban掉)了{LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "chi" "一个队长在Veto(Ban图)期间离开,暂停Veto(Ban图)" - } - "ReadyToResumeVetoInfoMessage" - { - "chi" "当您准备好恢复Veto(Ban图)时,请输入{GREEN}!ready{NORMAL}。" - } - "MatchConfigLoadedInfoMessage" - { - "chi" "已加载比赛配置。" - } - "MoveToCoachInfoMessage" - { - "chi" "因为您的团队已经满员,所以您被移到了教练的位置。" - } - "ReadyTag" - { - "chi" "[准备]" - } - "NotReadyTag" - { - "chi" "[未准备]" - } - "MatchPoweredBy" - { - "chi" "由{YELLOW}Get5{NORMAL}强力驱动" - } - "MapVetoPickMenuText" - { - "chi" "请选择一张想玩的地图:" - } - "MapVetoPickConfirmMenuText" - { - "chi" "你确定想玩{1}:" - } - "MapVetoBanMenuText" - { - "chi" "请选择一张想VETO(Ban图)的地图:" - } - "MapVetoBanConfirmMenuText" - { - "chi" "你确定想VETO(Ban图){1}:" - } - "MapVetoSidePickMenuText" - { - "chi" "请为{1}选择队伍" - } - "MapVetoSidePickConfirmMenuText" - { - "chi" "你确定想开始{1}:" - } - "ConfirmPositiveOptionText" - { - "chi" "是" - } - "ConfirmNegativeOptionText" - { - "chi" "否" - } - "VetoCountdown" - { - "chi" "Veto(Ban图)还剩{GREEN}{1}秒。" - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/de/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/de/get5.phrases.txt deleted file mode 100644 index 22a95ae..0000000 --- a/sourcemod_plugin/get5_apistats/translations/de/get5.phrases.txt +++ /dev/null @@ -1,243 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "de" "Tippe {GREEN}!ready {NORMAL}wenn dein Team bereit zum Voten ist." - } - "WaitingForCastersReadyInfoMessage" - { - "de" "Warten auf die Caster, tippe {GREEN}!ready {NORMAL}um zu beginnen." - } - "ReadyToRestoreBackupInfoMessage" - { - "de" "Tippe {GREEN}!ready {NORMAL}wenn dein Team bereit ist das Match Backup wieder einzuspielen." - } - "ReadyToKnifeInfoMessage" - { - "de" "Tippe {GREEN}!ready {NORMAL}wenn dein Team bereit ist für die Messer-Runde." - } - "ReadyToStartInfoMessage" - { - "de" "Tippe {GREEN}!ready {NORMAL}wenn dein Team bereit ist zu beginnen." - } - "WaitingForEnemySwapInfoMessage" - { - "de" "{1} gewinnt die Seitenwahl. Wartend auf !stay oder !swap ." - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "de" "Die Map wird gewechselt sobald der GOTV broadcast geendet hat." - } - "NoMatchSetupInfoMessage" - { - "de" "Es ist kein Match aufgesetzt" - } - "YourAreNotAPlayerInfoMessage" - { - "de" "Du bist kein Spieler von diesem Match" - } - "TeamIsFullInfoMessage" - { - "de" "Dein Team ist voll" - } - "TeamForfeitInfoMessage" - { - "de" "{1} schaffte es nicht fertig zu werden und gab auf." - } - "MinutesToForfeitMessage" - { - "de" "{1} hat {2} Minuten um fertig zu werden oder sie werden aufgeben." - } - "SecondsToForfeitInfoMessage" - { - "de" "{1} hat {2} Sekunden um fertig zu werden oder sie werden aufgeben." - } - "10SecondsToForfeitInfoMessage" - { - "de" "{1} hat 10 Sekunden fertig zu werden oder sie geben auf." - } - "PausePeriodSuffix" - { - "de" "für diese Hälfte" - } - "MaxPausesUsedInfoMessage" - { - "de" "Dein Team hatte bereits die maximal zulässigen {1} Pausen{2}." - } - "MaxPausesTimeUsedInfoMessage" - { - "de" "Dein Team hat bereits die maximalen {1} Sekunden der Pausezeit genutzt{2}." - } - "MatchPausedByTeamMessage" - { - "de" "{1} hat das Match pausiert." - } - "PauseTimeExpiration10SecInfoMessage" - { - "de" "{1} hat fast keine Pausenzeit mehr, es wird in 10 Sekunden fortgefahren." - } - "PauseTimeExpirationInfoMessage" - { - "de" "{1} hat {2} Sekunden der Pausenzeit übrig{3}." - } - "PauseRunoutInfoMessage" - { - "de" "{1} hat keine Pausenzeit mehr, weiter gehts!" - } - "MatchUnpauseInfoMessage" - { - "de" "{1:N} hat das Match fortgesetzt." - } - "WaitingForUnpauseInfoMessage" - { - "de" "{1} möchte fortfahren, zum zuzustimmen muss {2} !unpause schreiben." - } - "TeamFailToReadyMinPlayerCheck" - { - "de" "Du musst mindestens {1} Spieler im Team haben um loszulegen." - } - "TeamReadyToVetoInfoMessage" - { - "de" "{1} ist bereit für die Mapwahl." - } - "TeamReadyToRestoreBackupInfoMessage" - { - "de" "{1} ist bereit ein Match Backup wieder einzuspielen." - } - "TeamReadyToKnifeInfoMessage" - { - "de" "{1} ist bereit für die Messerrunde." - } - "TeamReadyToBeginInfoMessage" - { - "de" "{1} ist bereit das Match zu beginnen." - } - "TeamNotReadyInfoMessage" - { - "de" "{1} ist nicht mehr bereit." - } - "AdminForceReadyInfoMessage" - { - "de" "Ein Admin hat das Match gestartet." - } - "AdminForceEndInfoMessage" - { - "de" "Ein Admin hat das Match beendet." - } - "AdminForcePauseInfoMessage" - { - "de" "Ein Admin hat das Match pausiert." - } - "AdminForceUnPauseInfoMessage" - { - "de" "Ein Admin hat das Match fortgesetzt." - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "de" "{1} möchte die letzte Runde wiederholen, {2} muss mit !stop bestätigen." - } - "TeamWinningSeriesInfoMessage" - { - "de" "{1}{NORMAL} gewinnt die Serie {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "de" "Die Serie ist unentschieden mit {1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "de" "Die nächste Map in der Serie ist {GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "de" "{1} hat das Match gewonnen." - } - "TeamsSplitSeriesBO2InfoMessage" - { - "de" "{1} und {2} haben die Serie 1-1 geteilt." - } - "TeamWonSeriesInfoMessage" - { - "de" "{1} hat die Serie gewonnen {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "de" "Das Match ist beendet" - } - "CurrentScoreInfoMessage" - { - "de" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "de" "Backup {1} erfolgreich geladen" - } - "MatchBeginInSecondsInfoMessage" - { - "de" "Das Match beginnt in {1} Sekunden." - } - "MatchIsLiveInfoMessage" - { - "de" "Match ist {GREEN}LIVE" - } - "KnifeIn5SecInfoMessage" - { - "de" "Die Messerrunde beginnt in 5 Sekunden." - } - "KnifeInfoMessage" - { - "de" "Messern!" - } - "TeamDecidedToStayInfoMessage" - { - "de" "{1} hat sich für den Stay entschieden." - } - "TeamDecidedToSwapInfoMessage" - { - "de" "{1} hat sich für den Seitenwechsel entschieden." - } - "TeamLostTimeToDecideInfoMessage" - { - "de" "{1} wird so bleiben da keine Entscheidung in der Zeit gefallen ist." - } - "ChangingMapInfoMessage" - { - "de" "Ändern der Map in {GREEN}{1}..." - } - "MapDecidedInfoMessage" - { - "de" "Die Maps wurden entschieden:" - } - "MapIsInfoMessage" - { - "de" "Map {1}: {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "de" "{1} wählte {GREEN}{2} {NORMAL}als Map aus {3}" - } - "TeamSelectSideInfoMessage" - { - "de" "{1} möchte als {GREEN}{2} {NORMAL}starten {3}" - } - "TeamVetoedMapInfoMessage" - { - "de" "{1} verbietet {LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "de" "Team Captian verließ das Match während der Veto Phase, pausieren..." - } - "ReadyToResumeVetoInfoMessage" - { - "de" "Tippe {GREEN}!ready {NORMAL}wenn ihr fertig seit mit dem veto fortzufahren." - } - "MatchConfigLoadedInfoMessage" - { - "de" "Match Config geladen." - } - "MoveToCoachInfoMessage" - { - "de" "Das Team ist voll die wurdest als Coach hinzugefügt." - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/fr/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/fr/get5.phrases.txt deleted file mode 100644 index df158a7..0000000 --- a/sourcemod_plugin/get5_apistats/translations/fr/get5.phrases.txt +++ /dev/null @@ -1,275 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "fr" "Entrez {GREEN}!ready {NORMAL}quand votre équipe est prête pour le tour de veto." - } - "WaitingForCastersReadyInfoMessage" - { - "fr" "En attente : les casters doivent entrer {GREEN}!ready {NORMAL}pour que le match commence." - } - "ReadyToRestoreBackupInfoMessage" - { - "fr" "Entrez {GREEN}!ready {NORMAL}quand vous êtes prêt(e) à restorer la sauvegarde du match." - } - "ReadyToKnifeInfoMessage" - { - "fr" "Entrez {GREEN}!ready {NORMAL}quand pour être prêt(e) pour à démarrer un round au couteau." - } - "ReadyToStartInfoMessage" - { - "fr" "Entrez {GREEN}!ready {NORMAL}quand vous êtes prêt(e) à commencer." - } - "YouAreReady" - { - "fr" "Vous avez été marqué(e) comme prêt(e)." - } - "YouAreNotReady" - { - "fr" "Vous avez été marqué(e) comme NON prêt(e)." - } - "WaitingForEnemySwapInfoMessage" - { - "fr" "{1} a gagné le round a couteau. Attente de leur choix entre !stay ou !swap." - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "fr" "La carte changera dès que la diffusion GOTV sera terminée." - } - "NoMatchSetupInfoMessage" - { - "fr" "Aucune configuration de match trouvée" - } - "YourAreNotAPlayerInfoMessage" - { - "fr" "Vous n'êtes pas un joueur dans ce match" - } - "TeamIsFullInfoMessage" - { - "fr" "Votre équipe est pleine" - } - "TeamForfeitInfoMessage" - { - "fr" "{1} ne s'est pas déclaré prête à temps et a déclaré forfait." - } - "MinutesToForfeitMessage" - { - "fr" "{1} dispose encore de {2} minutes pour se déclarer prête, sinon elle déclarera forfait." - } - "SecondsToForfeitInfoMessage" - { - "fr" "{1} dispose encore de {2} secondes pour se déclarer prête, sinon elle déclarera forfait." - } - "10SecondsToForfeitInfoMessage" - { - "fr" "{1} a 10 secondes pour se déclarer prêt(e), sinon il/elle déclarera forfait." - } - "PausePeriodSuffix" - { - "fr" "pour cette mi-temps" - } - "MaxPausesUsedInfoMessage" - { - "fr" "Votre équipe a déjà utilisé son maximum de {1} pauses{2}." - } - "MaxPausesTimeUsedInfoMessage" - { - "fr" "Votre équipe a déjà utilisé son maximum de {1} secondes de pause{2}." - } - "MatchPausedByTeamMessage" - { - "fr" "{1} a mis le match en pause." - } - "PauseTimeExpiration10SecInfoMessage" - { - "fr" "{1} est bientôt parvenue à la fin de sa pause, fin dans 10 secondes." - } - "PauseTimeExpirationInfoMessage" - { - "fr" "{1} dispose encore de {2} secondes de pause{3}." - } - "PauseRunoutInfoMessage" - { - "fr" "{1} a épuisé son temps de pause, reprise du match." - } - "MatchUnpauseInfoMessage" - { - "fr" "{1:N} a mis fin à la pause." - } - "WaitingForUnpauseInfoMessage" - { - "fr" "{1} désire reprendre le match, en attente que {2} tappe !unpause." - } - "PausesLeftInfoMessage" - { - "fr" "{1} dispose encore de {2} pauses{3}." - } - "OnePauseLeftInfoMessage" - { - "fr" "{1} dispose encore de {2} pause{3}." - } - "TeamFailToReadyMinPlayerCheck" - { - "fr" "Vous devez disposer d'au moins {1} joueur sur le serveur pour vous déclarer prêt(e)." - } - "TeamReadyToVetoInfoMessage" - { - "fr" "{1} est prêt pour le tour de veto." - } - "TeamReadyToRestoreBackupInfoMessage" - { - "fr" "{1} est prêt à restaurer la sauvegarde du match." - } - "TeamReadyToKnifeInfoMessage" - { - "fr" "{1} est prêt pour le knife round." - } - "TeamReadyToBeginInfoMessage" - { - "fr" "{1} est prêt à commencer le match." - } - "TeamNotReadyInfoMessage" - { - "fr" "{1} n'est plus prêt." - } - "ForceReadyInfoMessage" - { - "fr" "Vous pouvez entrer {GREEN}!forceready {NORMAL}pour forcer votre équipe à être prête si vous avez moins de {GREEN}{1}{NORMAL} joueurs." - } - "TeammateForceReadied" - { - "fr" "Votre équipe s'est déclaré prête (de force) par {GREEN}{1}" - } - "AdminForceReadyInfoMessage" - { - "fr" "Un admin a forcé toutes les équipes à se déclarer prêtes." - } - "AdminForceEndInfoMessage" - { - "fr" "Un admin a forcé la fin du match." - } - "AdminForcePauseInfoMessage" - { - "fr" "Un admin a forcé le match en pause." - } - "AdminForceUnPauseInfoMessage" - { - "fr" "Un admin a forcé la reprise du match." - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "fr" "{1} veut arrêter et recommencer au dernier round, cela nécessite {2} pour confirmer avec !stop." - } - "TeamWinningSeriesInfoMessage" - { - "fr" "{1}{NORMAL} gagne les séries {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "fr" "La série est ex-æquo at {1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "fr" "La prochaine map dans la série est {GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "fr" "{1} a remporté la victoire." - } - "TeamsSplitSeriesBO2InfoMessage" - { - "fr" "{1} et {2} ont gagné autant de match (1-1)." - } - "TeamWonSeriesInfoMessage" - { - "fr" "{1} a remporté la série {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "fr" "Le match est terminé" - } - "CurrentScoreInfoMessage" - { - "fr" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "fr" "Sauvegarde chargée avec succès {1}" - } - "MatchBeginInSecondsInfoMessage" - { - "fr" "Le match commencera dans {1} secondes." - } - "MatchIsLiveInfoMessage" - { - "fr" "Le match est en {GREEN}LIVE" - } - "KnifeIn5SecInfoMessage" - { - "fr" "Le knife round commencera dans 5 secondes." - } - "KnifeInfoMessage" - { - "fr" "Knife !" - } - "TeamDecidedToStayInfoMessage" - { - "fr" "{1} a décidé de rester." - } - "TeamDecidedToSwapInfoMessage" - { - "fr" "{1} a décidé de changer de camp." - } - "TeamLostTimeToDecideInfoMessage" - { - "fr" "{1} restera car ils n'ont pas pris leur décision à temps." - } - "ChangingMapInfoMessage" - { - "fr" "Changement de map pour {GREEN}{1}…" - } - "MapDecidedInfoMessage" - { - "fr" "Les maps ont été décidées :" - } - "MapIsInfoMessage" - { - "fr" "Map {1} : {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "fr" "{1} a choisi {GREEN}{2} {NORMAL}comme map {3}" - } - "TeamSelectSideInfoMessage" - { - "fr" "{1} a choisi de commencer sur {GREEN}{2} {NORMAL}sur {3}" - } - "TeamVetoedMapInfoMessage" - { - "fr" "{1} a rejetté {LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "fr" "Un chef d'équipe a quitté pendant le tour de veto, match en pause." - } - "ReadyToResumeVetoInfoMessage" - { - "fr" "Entrez {GREEN}!ready {NORMAL}quand vous êtes prêt(e) à reprendre le tour de veto." - } - "MatchConfigLoadedInfoMessage" - { - "fr" "Configuration du match chargée." - } - "MoveToCoachInfoMessage" - { - "fr" "Vous avez bougé à la position de coach, car votre équipe est complète." - } - "ReadyTag" - { - "fr" "[PRÊT]" - } - "NotReadyTag" - { - "fr" "[PAS PRÊT]" - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/get5.phrases.txt deleted file mode 100644 index d149fd6..0000000 --- a/sourcemod_plugin/get5_apistats/translations/get5.phrases.txt +++ /dev/null @@ -1,380 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "en" "Type {GREEN}!ready {NORMAL}when your team is ready to veto." - } - "WaitingForCastersReadyInfoMessage" - { - "#format" "{1:s}" - "en" "Waiting for {1} to type {GREEN}!ready {NORMAL}to begin." - } - "ReadyToRestoreBackupInfoMessage" - { - "en" "Type {GREEN}!ready {NORMAL}when you are ready to restore the match backup." - } - "ReadyToKnifeInfoMessage" - { - "en" "Type {GREEN}!ready {NORMAL}when you are ready to knife." - } - "ReadyToStartInfoMessage" - { - "en" "Type {GREEN}!ready {NORMAL}when you are ready to begin." - } - "YouAreReady" - { - "en" "You have been marked as ready." - } - "YouAreNotReady" - { - "en" "You have been marked as NOT ready." - } - "WaitingForEnemySwapInfoMessage" - { - "#format" "{1:s}" - "en" "{1} won the knife round. Waiting for them to type !stay or !swap." - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "en" "The map will change once the GOTV broadcast has ended." - } - "WaitingForGOTVVetoInfoMessage" - { - "en" "The map will change once the GOTV broadcast has been displayed the map vetos." - } - "NoMatchSetupInfoMessage" - { - "en" "There is no match setup" - } - "YourAreNotAPlayerInfoMessage" - { - "en" "You are not a player in this match" - } - "TeamIsFullInfoMessage" - { - "en" "Your team is full" - } - "TeamForfeitInfoMessage" - { - "#format" "{1:s}" - "en" "{1} failed to ready up in time and has forfeit." - } - "MinutesToForfeitMessage" - { - "#format" "{1:s},{2:d}" - "en" "{1} has {2} minutes left to ready up or they will forfeit the match." - } - "SecondsToForfeitInfoMessage" - { - "#format" "{1:s},{2:d}" - "en" "{1} has {2} seconds left to ready up or they will forfeit the match." - } - "10SecondsToForfeitInfoMessage" - { - "#format" "{1:s}" - "en" "{1} has 10 seconds to ready up or forfeit the match." - } - "PausePeriodSuffix" - { - "en" "for this half" - } - "MaxPausesUsedInfoMessage" - { - "#format" "{1:d},{2:s}" - "en" "Your team has already used the max {1} pauses{2}." - } - "MaxPausesTimeUsedInfoMessage" - { - "#format" "{1:d},{2:s}" - "en" "Your team has already used the max {1} seconds of pause time{2}." - } - "MatchPausedByTeamMessage" - { - "#format" "{1:N}" - "en" "{1} paused the match." - } - "MatchTechPausedByTeamMessage" - { - "#format" "{1:N}" - "en" "{1} has called for a technical pause." - } - "AdminForceTechPauseInfoMessage" - { - "en" "An admin has called for a technical pause." - } - "PauseTimeExpiration10SecInfoMessage" - { - "#format" "{1:s}" - "en" "{1} is almost out of pause time, unpausing in 10 seconds." - } - "PauseTimeExpirationInfoMessage" - { - "#format" "{1:s},{2:d},{3:s}" - "en" "{1} has {2} seconds of pause time left{3}." - } - "PauseRunoutInfoMessage" - { - "#format" "{1:s}" - "en" "{1} has run out of pause time, unpausing the match." - } - "MatchUnpauseInfoMessage" - { - "#format" "{1:N}" - "en" "{1:N} unpaused the match." - } - "WaitingForUnpauseInfoMessage" - { - "#format" "{1:s},{2:s}" - "en" "{1} wants to unpause, waiting for {2} to type !unpause." - } - "PausesLeftInfoMessage" - { - "#format" "{1:s},{2:d},{3:s}" - "en" "{1} has {2} pauses left{3}." - } - "OnePauseLeftInfoMessage" - { - "#format" "{1:s},{2:d},{3:s}" - "en" "{1} has {2} pause left{3}." - } - "TeamFailToReadyMinPlayerCheck" - { - "#format" "{1:d}" - "en" "You must have at least {1} players on the server to ready up." - } - "TeamReadyToVetoInfoMessage" - { - "#format" "{1:s}" - "en" "{1} is ready to veto." - } - "TeamReadyToRestoreBackupInfoMessage" - { - "#format" "{1:s}" - "en" "{1} is ready to restore the match backup." - } - "TeamReadyToKnifeInfoMessage" - { - "#format" "{1:s}" - "en" "{1} is ready to knife for sides." - } - "TeamReadyToBeginInfoMessage" - { - "#format" "{1:s}" - "en" "{1} is ready to begin the match." - } - "TeamNotReadyInfoMessage" - { - "#format" "{1:s}" - "en" "{1} is no longer ready." - } - "ForceReadyInfoMessage" - { - "#format" "{1:d}" - "en" "You may type {GREEN}!forceready {NORMAL}to force ready your team if you have less than {GREEN}{1}{NORMAL} players." - } - "TeammateForceReadied" - { - "#format" "{1:N}" - "en" "Your team was force-readied by {GREEN}{1}" - } - "AdminForceReadyInfoMessage" - { - "en" "An admin has force-readied all teams." - } - "AdminForceEndInfoMessage" - { - "en" "An admin force ended the match." - } - "AdminForcePauseInfoMessage" - { - "en" "An admin force paused the match." - } - "AdminForceUnPauseInfoMessage" - { - "en" "An admin force unpaused the match." - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "#format" "{1:s},{2:s}" - "en" "{1} wants to stop and reload last round, need {2} to confirm with !stop." - } - "TeamWinningSeriesInfoMessage" - { - "#format" "{1:s},{2:d},{3:d}" - "en" "{1}{NORMAL} is winning the series {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "#format" "{1:d},{2:d}" - "en" "The series is tied at {1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "#format" "{1:s}" - "en" "The next map in the series is {GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "#format" "{1:s}" - "en" "{1} has won the match." - } - "TeamTiedMatchInfoMessage" - { - "#format" "{1:s},{2:s}" - "en" "{1} and {2} have tied the match." - } - "TeamsSplitSeriesBO2InfoMessage" - { - "#format" "{1:s},{2:s}" - "en" "{1} and {2} have split the series 1-1." - } - "TeamWonSeriesInfoMessage" - { - "#format" "{1:s},{2:d},{3:d}" - "en" "{1} has won the series {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "en" "The match has been finished" - } - "CurrentScoreInfoMessage" - { - "#format" "{1:s},{2:d},{3:d},{4:s}" - "en" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "#format" "{1:s}" - "en" "Successfully loaded backup {1}" - } - "MatchBeginInSecondsInfoMessage" - { - "#format" "{1:d}" - "en" "The match will begin in {1} seconds." - } - "MatchIsLiveInfoMessage" - { - "en" "Match is {GREEN}LIVE" - } - "KnifeIn5SecInfoMessage" - { - "en" "The knife round will begin in 5 seconds." - } - "KnifeInfoMessage" - { - "en" "Knife!" - } - "TeamDecidedToStayInfoMessage" - { - "#format" "{1:s}" - "en" "{1} has decided to stay." - } - "TeamDecidedToSwapInfoMessage" - { - "#format" "{1:s}" - "en" "{1} has decided to swap." - } - "TeamLostTimeToDecideInfoMessage" - { - "#format" "{1:s}" - "en" "{1} will stay since they did not make a decision in time." - } - "ChangingMapInfoMessage" - { - "#format" "{1:s}" - "en" "Changing map to {GREEN}{1}..." - } - "MapDecidedInfoMessage" - { - "en" "The maps have been decided:" - } - "MapIsInfoMessage" - { - "#format" "{1:d},{2:s}" - "en" "Map {1}: {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "#format" "{1:s},{2:s},{3:d}" - "en" "{1} picked {GREEN}{2} {NORMAL}as map {3}" - } - "TeamSelectSideInfoMessage" - { - "#format" "{1:s},{2:s},{3:s}" - "en" "{1} has selected to start on {GREEN}{2} {NORMAL}on {3}" - } - "TeamVetoedMapInfoMessage" - { - "#format" "{1:s},{2:s}" - "en" "{1} vetoed {LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "en" "A captain left during the veto, pausing the veto." - } - "ReadyToResumeVetoInfoMessage" - { - "en" "Type {GREEN}!ready {NORMAL}when you are ready to resume the veto." - } - "MatchConfigLoadedInfoMessage" - { - "en" "Loaded match config." - } - "MoveToCoachInfoMessage" - { - "en" "Because your team is full, you were moved to the coach position." - } - "ReadyTag" - { - "en" "[READY]" - } - "NotReadyTag" - { - "en" "[NOT READY]" - } - "MatchPoweredBy" - { - "en" "Powered by {YELLOW}Get5" - } - "MapVetoPickMenuText" - { - "en" "Select a map to PLAY:" - } - "MapVetoPickConfirmMenuText" - { - "#format" "{1:s}" - "en" "Confirm you want to PLAY {1}:" - } - "MapVetoBanMenuText" - { - "en" "Select a map to VETO:" - } - "MapVetoBanConfirmMenuText" - { - "#format" "{1:s}" - "en" "Confirm you want to VETO {1}:" - } - "MapVetoSidePickMenuText" - { - "#format" "{1:s}" - "en" "Select a side for {1}" - } - "MapVetoSidePickConfirmMenuText" - { - "#format" "{1:s}" - "en" "Confirm you want to start {1}:" - } - "ConfirmPositiveOptionText" - { - "en" "Yes" - } - "ConfirmNegativeOptionText" - { - "en" "No" - } - "VetoCountdown" - { - "#format" "{1:i}" - "en" "Veto commencing in {GREEN}{1} {NORMAL}seconds." - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/pl/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/pl/get5.phrases.txt deleted file mode 100644 index 8c51592..0000000 --- a/sourcemod_plugin/get5_apistats/translations/pl/get5.phrases.txt +++ /dev/null @@ -1,251 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "pl" "Napisz {GREEN}!ready {NORMAL}kiedy Twoja drużyna będzie gotowa do głosowania." - } - "WaitingForCastersReadyInfoMessage" - { - "pl" "Czekamy na komentatorów na wpisanie {GREEN}!ready {NORMAL}aby zacząć rozgrywkę." - } - "ReadyToRestoreBackupInfoMessage" - { - "pl" "Napisz {GREEN}!ready {NORMAL}kiedy Twoja drużyna będzie gotowa do wczytania meczu." - } - "ReadyToKnifeInfoMessage" - { - "pl" "Napisz {GREEN}!ready {NORMAL}kiedy Twoja drużyna będzie gotowa do rundy nożowej." - } - "ReadyToStartInfoMessage" - { - "pl" "Napisz {GREEN}!ready {NORMAL}kiedy Twoja drużyna będzie gotowa." - } - "WaitingForEnemySwapInfoMessage" - { - "pl" "{1} wygralo runde nożową. Oczekiwanie na !stay lub !swap." - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "pl" "Mapa zostanie zmieniona gdy transmisja GOTV zostanie zakończona." - } - "NoMatchSetupInfoMessage" - { - "pl" "Brak ustawień meczu" - } - "YourAreNotAPlayerInfoMessage" - { - "pl" "Nie jesteś graczem w tym meczu" - } - "TeamIsFullInfoMessage" - { - "pl" "Twoja drużyna jest pełna" - } - "TeamForfeitInfoMessage" - { - "pl" "{1} nie bylo gotowe w wymaganym czasie i mecz został oddany na korzyść drużyny przeciwnej." - } - "MinutesToForfeitMessage" - { - "pl" "{1} ma {2} minuty aby być gotowym do meczu albo mecz zostanie oddany na korzyść drużyny przeciwnej." - } - "SecondsToForfeitInfoMessage" - { - "pl" "{1} ma {2} sekund aby być gotowym do meczu albo mecz zostanie oddany na korzyść drużyny przeciwnej." - } - "10SecondsToForfeitInfoMessage" - { - "pl" "{1} ma 10 sekund aby być gotowym do meczu albo mecz zostanie oddany na korzyść drużyny przeciwnej." - } - "PausePeriodSuffix" - { - "pl" "na tę połowę" - } - "MaxPausesUsedInfoMessage" - { - "pl" "Twoja drużyna użyła już maksymalnie {1} pauzy{2}." - } - "MaxPausesTimeUsedInfoMessage" - { - "pl" "Twoja drużyna użyła już maksymalnie {1} sekund czasu pauzy{2}." - } - "MatchPausedByTeamMessage" - { - "pl" "{1} zatrzymało mecz." - } - "PauseTimeExpiration10SecInfoMessage" - { - "pl" "{1} kończy się czas pauzy, wznowienie rozgrywki nastąpi za 10 sekund." - } - "PauseTimeExpirationInfoMessage" - { - "pl" "{1} zostało {2} sekund pauzy{3}." - } - "PauseRunoutInfoMessage" - { - "pl" "{1} skończył się czas pauzy, wznawianie rozgrywki." - } - "MatchUnpauseInfoMessage" - { - "pl" "{1:N} odpauzowało mecz." - } - "WaitingForUnpauseInfoMessage" - { - "pl" "{1} chce wznowić rozgrywkę, oczekiwanie na {2} na wpisanie !unpause." - } - "PausesLeftInfoMessage" - { - "pl" "{1} pozostały {2} pauzy{3}." - } - "OnePauseLeftInfoMessage" - { - "pl" "{1} pozostała {2} pauza{3}." - } - "TeamFailToReadyMinPlayerCheck" - { - "pl" "Musi być conajmniej {1}graczy na serwerze aby móc być gotowym." - } - "TeamReadyToVetoInfoMessage" - { - "pl" "{1} jest gotowe do głosowania." - } - "TeamReadyToRestoreBackupInfoMessage" - { - "pl" "{1} jest gotowe do przywrócenia meczu." - } - "TeamReadyToKnifeInfoMessage" - { - "pl" "{1} jest gotowe do nożówki za strony." - } - "TeamReadyToBeginInfoMessage" - { - "pl" "{1} jest gotowe do rozpoczęcia meczu." - } - "TeamNotReadyInfoMessage" - { - "pl" "{1} anulowali swoją gotowość." - } - "AdminForceReadyInfoMessage" - { - "pl" "Administrator wymusił gotowość na wszystkich drużynach." - } - "AdminForceEndInfoMessage" - { - "pl" "Administrator zakończył mecz." - } - "AdminForcePauseInfoMessage" - { - "pl" "Administrator zatrzymał mecz." - } - "AdminForceUnPauseInfoMessage" - { - "pl" "Administrator wznowił mecz." - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "pl" "{1} chce zatrzymać mecz i wczytać poprzednią rundę, oczekiwanie na potwierdzenie przez {2} i wpisanie !stop." - } - "TeamWinningSeriesInfoMessage" - { - "pl" "{1}{NORMAL} wygrywa {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "pl" "Drużyny remisują {1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "pl" "Następna mapa w meczu to {GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "pl" "{1} wygrało mapę." - } - "TeamsSplitSeriesBO2InfoMessage" - { - "pl" "{1} i {2} zremisowali spotkanie 1-1." - } - "TeamWonSeriesInfoMessage" - { - "pl" "{1} wygrało spotkanie {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "pl" "Mecz został zakończony" - } - "CurrentScoreInfoMessage" - { - "pl" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "pl" "Pomyślnie wczytano kopię meczu {1}" - } - "MatchBeginInSecondsInfoMessage" - { - "pl" "Mecz rozpocznie się za {1} sekund." - } - "MatchIsLiveInfoMessage" - { - "pl" "Mecz jest {GREEN}LIVE" - } - "KnifeIn5SecInfoMessage" - { - "pl" "Runda nożowa rozpocznie się za 5 sekund." - } - "KnifeInfoMessage" - { - "pl" "Nozówka!" - } - "TeamDecidedToStayInfoMessage" - { - "pl" "{1} zdecydowało na pozostanie w aktualnych drużynach." - } - "TeamDecidedToSwapInfoMessage" - { - "pl" "{1} zdecydowało na zamianę drużyn." - } - "TeamLostTimeToDecideInfoMessage" - { - "pl" "{1} drużyny zostały w aktualnych drużynach, ponieważ żadna decyzja nie została podjęta." - } - "ChangingMapInfoMessage" - { - "pl" "Zmiana mapy na {GREEN}{1}..." - } - "MapDecidedInfoMessage" - { - "pl" "Wybrano następujące mapy:" - } - "MapIsInfoMessage" - { - "pl" "Mapa {1}: {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "pl" "{1} wybrało {GREEN}{2} {NORMAL}jako mapę {3}" - } - "TeamSelectSideInfoMessage" - { - "pl" "{1} wybrało stronę {GREEN}{2} {NORMAL}na {3}" - } - "TeamVetoedMapInfoMessage" - { - "pl" "{1} odrzuciło {LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "pl" "Kapitan opuścił serwer, głosowanie zostało wstrzymane." - } - "ReadyToResumeVetoInfoMessage" - { - "pl" "Napisz {GREEN}!ready {NORMAL}kiedy Twoja drużyna będzie gotowa do wznowienia głosowania." - } - "MatchConfigLoadedInfoMessage" - { - "pl" "Załadowano ustawawienia meczu." - } - "MoveToCoachInfoMessage" - { - "pl" "Ponieważ Twoja drużyna jest pełna, zostałeś przeniesiony na stanowisko coach'a." - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/pt/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/pt/get5.phrases.txt deleted file mode 100644 index 6f5feb9..0000000 --- a/sourcemod_plugin/get5_apistats/translations/pt/get5.phrases.txt +++ /dev/null @@ -1,279 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "pt" "Digite {GREEN}!ready {NORMAL}quando seu time estiver pronto para o veto." - } - "WaitingForCastersReadyInfoMessage" - { - "pt" "Esperando pelos streammers para digitar {GREEN}!ready {NORMAL}pra começar." - } - "ReadyToRestoreBackupInfoMessage" - { - "pt" "Digite {GREEN}!ready {NORMAL}quando vocês estiver pronto para restaurar o backup da partida." - } - "ReadyToKnifeInfoMessage" - { - "pt" "Digite {GREEN}!ready {NORMAL}quando você estiver pronto pro Round Faca." - } - "ReadyToStartInfoMessage" - { - "pt" "Digite {GREEN}!ready {NORMAL}quando você estiver pronto para começar." - } - "YouAreReady" - { - "pt" "Você foi marcado como {GREEN}pronto{NORMAL}." - } - "YouAreNotReady" - { - "pt" "Você foi desmarcado como {GREEN}pronto{NORMAL}." - } - "WaitingForEnemySwapInfoMessage" - { - "pt" "{1} venceu o Round Faca. Esperando pelo time vencedor digitar !stay ou !swap." - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "pt" "O mapa vai mudar assim que o broadcast do GOTV acabar." - } - "NoMatchSetupInfoMessage" - { - "pt" "Não existe configuração de partida." - } - "YourAreNotAPlayerInfoMessage" - { - "pt" "Você não é um jogador dessa partida." - } - "TeamIsFullInfoMessage" - { - "pt" "Seu time está cheio." - } - "TeamForfeitInfoMessage" - { - "pt" "{1} não ficou pronto a tempo e se rendeu." - } - "MinutesToForfeitMessage" - { - "pt" "{1} tem {2} minutos para ficar prontos ou eles se renderão." - } - "SecondsToForfeitInfoMessage" - { - "pt" "{1} tem {2} segundos para ficar prontos ou eles se renderão." - } - "10SecondsToForfeitInfoMessage" - { - "pt" "{1} tem 10 segundos para fica prontos ou se render." - } - "PausePeriodSuffix" - { - "pt" "para essa metade do jogo." - } - "MaxPausesUsedInfoMessage" - { - "pt" "Seu time já utilizou o máximo de {1} pausas{2}." - } - "MaxPausesTimeUsedInfoMessage" - { - "pt" "Seu time já usou o máximo de {1} segundos do tempo de pausa{2}." - } - "MatchPausedByTeamMessage" - { - "pt" "{1} pausou a partida." - } - "PauseTimeExpiration10SecInfoMessage" - { - "pt" "{1} está quase no fim do tempo de pausa, resumindo a partida em 10 segundos." - } - "PauseTimeExpirationInfoMessage" - { - "pt" "{1} tem {2} segundos faltando para resumir a partida{3}." - } - "PauseRunoutInfoMessage" - { - "pt" "{1} chegou ao fim do tmepo de pause, resumindo a partida." - } - "MatchUnpauseInfoMessage" - { - "pt" "{1:N} resumiu a partida." - } - "WaitingForUnpauseInfoMessage" - { - "pt" "{1} quer resumir a partida, mas esperando por {2} digitar !unpause." - } - "PausesLeftInfoMessage" - { - "pt" "{1} tem {2} pauses sobrando{3}." - } - "OnePauseLeftInfoMessage" - { - "pt" "{1} tem {2} pause sobrando{3}." - } - "TeamFailToReadyMinPlayerCheck" - { - "pt" "Você precisa ter pelo menos {1} jogadores conectados no server para ficar pronto." - } - "TeamReadyToVetoInfoMessage" - { - "pt" "{1} está pronto para o veto." - } - "TeamReadyToRestoreBackupInfoMessage" - { - "pt" "{1} está pronto para restaurar o backup da partida." - } - "TeamReadyToKnifeInfoMessage" - { - "pt" "{1} está pronto para jogar o Round Faca." - } - "TeamReadyToBeginInfoMessage" - { - "pt" "{1} está pronto para começar a partida." - } - "TeamNotReadyInfoMessage" - { - "pt" "{1} deixou de estar pronto." - } - "ForceReadyInfoMessage" - { - "pt" "Você pode digitar {GREEN}!forceready {NORMAL}para forçar seu time a ficar pronto se você tiver menos de {GREEN}{1}{NORMAL} jogador." - } - "TeammateForceReadied" - { - "pt" "Seu time foi forçado a ficar pronto pelo jogador {GREEN}{1}" - } - "AdminForceReadyInfoMessage" - { - "pt" "O administrador forçou todos os times a ficarem prontos." - } - "AdminForceEndInfoMessage" - { - "pt" "O administrador forçou o fim da partida." - } - "AdminForcePauseInfoMessage" - { - "pt" "O administrador forçou um pause na partida." - } - "AdminForceUnPauseInfoMessage" - { - "pt" "O administrador forçou o resumo de uma partida." - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "pt" "{1} quer parar e recomeçar o último round. Para isso precisa que outros {2} confirmem digitanto !stop." - } - "TeamWinningSeriesInfoMessage" - { - "pt" "{1}{NORMAL} está vencendo a série {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "pt" "A série está empatada em {1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "pt" "O próximo mapa da série será {GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "pt" "{1} é a equipe vencedora da partida." - } - "TeamsSplitSeriesBO2InfoMessage" - { - "pt" "{1} e {2} empataram a série em 1-1." - } - "TeamWonSeriesInfoMessage" - { - "pt" "{1} é a equipe vencedora da série {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "pt" "A partida foi fnializada." - } - "CurrentScoreInfoMessage" - { - "pt" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "pt" "Backup carregado com sucesso {1}" - } - "MatchBeginInSecondsInfoMessage" - { - "pt" "A partida vai começar em {1} segundos." - } - "MatchIsLiveInfoMessage" - { - "pt" "{GREEN}Começou a partida! Boa diversão e boa sorte!" - } - "KnifeIn5SecInfoMessage" - { - "pt" "O Round Faca vai começar em 5 segundos." - } - "KnifeInfoMessage" - { - "pt" "Round Faca!" - } - "TeamDecidedToStayInfoMessage" - { - "pt" "{1} decidiu ficar no mesmo lado." - } - "TeamDecidedToSwapInfoMessage" - { - "pt" "{1} decidiu trocar de lado." - } - "TeamLostTimeToDecideInfoMessage" - { - "pt" "{1} ficará no mesmo lado uma vez que não decidiu a tempo." - } - "ChangingMapInfoMessage" - { - "pt" "Mudando o mapa para {GREEN}{1}..." - } - "MapDecidedInfoMessage" - { - "pt" "Os mapas foram votados:" - } - "MapIsInfoMessage" - { - "pt" "Mapa {1}: {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "pt" "{1} escolheu {GREEN}{2} {NORMAL}como mapa {3}" - } - "TeamSelectSideInfoMessage" - { - "pt" "{1} escolheu começar no lado {GREEN}{2} {NORMAL}em {3}" - } - "TeamVetoedMapInfoMessage" - { - "pt" "{1} vetou {LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "pt" "Um capitão deixou a partida durante o veto, pausando o veto." - } - "ReadyToResumeVetoInfoMessage" - { - "pt" "Digite {GREEN}!ready {NORMAL}quando você estiver pronto para resumir o veto." - } - "MatchConfigLoadedInfoMessage" - { - "pt" "A configuração da partida foi carregada com sucesso." - } - "MoveToCoachInfoMessage" - { - "pt" "Você foi movido para a posição de Coach pois seu time está cheio." - } - "ReadyTag" - { - "pt" "[READY]" - } - "NotReadyTag" - { - "pt" "[NOT READY]" - } - "MatchPoweredBy" - { - "pt" "Oferecido por {YELLOW}Get5" - } -} diff --git a/sourcemod_plugin/get5_apistats/translations/ru/get5.phrases.txt b/sourcemod_plugin/get5_apistats/translations/ru/get5.phrases.txt deleted file mode 100644 index f6dd6fb..0000000 --- a/sourcemod_plugin/get5_apistats/translations/ru/get5.phrases.txt +++ /dev/null @@ -1,239 +0,0 @@ -"Phrases" -{ - "ReadyToVetoInfoMessage" - { - "ru" "Напишите {GREEN}!ready {NORMAL}когда ваша команда будет готова к голосованию." - } - "WaitingForCastersReadyInfoMessage" - { - "ru" "Ожидаем, пока все игроки напишут {GREEN}!ready {NORMAL}для начала." - } - "ReadyToRestoreBackupInfoMessage" - { - "ru" "Напиши {GREEN}!ready {NORMAL}когда твоя команда будет готова загрузить сохраненную игру." - } - "ReadyToKnifeInfoMessage" - { - "ru" "Напиши {GREEN}!ready {NORMAL}когда твоя команда будет готова к ножевому раунду." - } - "ReadyToStartInfoMessage" - { - "ru" "Напиши {GREEN}!ready {NORMAL}когда твоя команда будет готова начать." - } - "WaitingForEnemySwapInfoMessage" - { - "ru" "{1} выиграла раунд. Ожидаем, пока они напишут !stay или !swap." - } - "WaitingForGOTVBrodcastEndingInfoMessage" - { - "ru" "Карта будет изменена, когда закончится трансляция на GOTV." - } - "NoMatchSetupInfoMessage" - { - "ru" "На этом сервере нет матча." - } - "YourAreNotAPlayerInfoMessage" - { - "ru" "Ты не являешься участником текущего матча" - } - "TeamIsFullInfoMessage" - { - "ru" "Твоя команда заполнена" - } - "TeamForfeitInfoMessage" - { - "ru" "{1} не подтвердили участие и им было засчитано техническое поражение." - } - "MinutesToForfeitMessage" - { - "ru" "У {1} осталось {2} минут, чтобы подтвердить готовность или им будет засчитано техническое поражение." - } - "SecondsToForfeitInfoMessage" - { - "ru" "У {1} осталось {2} секунд, чтобы подтвердить готовность или им будет засчитано техническое поражение." - } - "10SecondsToForfeitInfoMessage" - { - "ru" "{1} осталось 10 секунд, чтобы подтвердить готовность." - } - "PausePeriodSuffix" - { - "ru" "для этой половины" - } - "MaxPausesUsedInfoMessage" - { - "ru" "Твоя команда уже израсходовала максимум {1} паузы{2}." - } - "MaxPausesTimeUsedInfoMessage" - { - "ru" "Твоя команда уже израсходовала максимум {1} секунд времени паузы{2}." - } - "MatchPausedByTeamMessage" - { - "ru" "{1} поставил матч на паузу." - } - "PauseTimeExpiration10SecInfoMessage" - { - "ru" "{1} уже израсходовали количество пауз, снятие с паузы через 10 секунд." - } - "PauseTimeExpirationInfoMessage" - { - "ru" "У {1} осталось {2} секунд от паузы{3}." - } - "PauseRunoutInfoMessage" - { - "ru" "Для {1} время паузы вышло, матч снимается с паузы." - } - "MatchUnpauseInfoMessage" - { - "ru" "{1} снял матч с паузы." - } - "WaitingForUnpauseInfoMessage" - { - "ru" "{1} желает снять паузу, ожидаем когда {2} напишут !unpause." - } - "TeamReadyToVetoInfoMessage" - { - "ru" "{1} готовы для голосования." - } - "TeamReadyToRestoreBackupInfoMessage" - { - "ru" "{1} готовы загрузить сохраненную игру." - } - "TeamReadyToKnifeInfoMessage" - { - "ru" "{1} готовы к ножевому раунду." - } - "TeamReadyToBeginInfoMessage" - { - "ru" "{1} готовы начать матч." - } - "TeamNotReadyInfoMessage" - { - "ru" "{1} пока не готовы." - } - "AdminForceReadyInfoMessage" - { - "ru" "Админ, в общем, сказал, что все готовы. Поехали." - } - "AdminForceEndInfoMessage" - { - "ru" "Админ завершил матч." - } - "AdminForcePauseInfoMessage" - { - "ru" "Администратор сила сделала паузу игра." - } - "AdminForceUnPauseInfoMessage" - { - "ru" "Администратор силы возобновленная игра." - } - "TeamWantsToReloadLastRoundInfoMessage" - { - "ru" "{1} желает остановить и перезагрузить последний раунд, ждем {2} чтобы написали !stop для подтверждения." - } - "TeamWinningSeriesInfoMessage" - { - "ru" "{1}{NORMAL} выигрывает со счетом {2}-{3}" - } - "SeriesTiedInfoMessage" - { - "ru" "Матч остановлен на счете {1}-{2}" - } - "NextSeriesMapInfoMessage" - { - "ru" "Следующая карта в серии {GREEN}{1}" - } - "TeamWonMatchInfoMessage" - { - "ru" "{1} выиграл матч." - } - "TeamsSplitSeriesBO2InfoMessage" - { - "ru" "{1} и {2} закончили серию со счетом 1-1." - } - "TeamWonSeriesInfoMessage" - { - "ru" "{1} выиграли серию {2}-{3}." - } - "MatchFinishedInfoMessage" - { - "ru" "Матч уже завершен" - } - "CurrentScoreInfoMessage" - { - "ru" "{LIGHT_GREEN}{1} {GREEN}{2} {NORMAL}- {GREEN}{3} {LIGHT_GREEN}{4}" - } - "BackupLoadedInfoMessage" - { - "ru" "Удачно загружен бэкап {1}" - } - "MatchBeginInSecondsInfoMessage" - { - "ru" "Матч начнется через {1} секунд." - } - "MatchIsLiveInfoMessage" - { - "ru" "Матч {GREEN}НАЧАЛСЯ!" - } - "KnifeIn5SecInfoMessage" - { - "ru" "Ножевой раунд начнется через 5 секунд." - } - "KnifeInfoMessage" - { - "ru" "Ножевой раунд!" - } - "TeamDecidedToStayInfoMessage" - { - "ru" "{1} решили остатся в той же команде." - } - "TeamDecidedToSwapInfoMessage" - { - "ru" "{1} решили сменить стороны." - } - "TeamLostTimeToDecideInfoMessage" - { - "ru" "{1} остаются в той же команде, так как они не успели принять решение вовремя." - } - "ChangingMapInfoMessage" - { - "ru" "Карта изменена на {GREEN}{1}..." - } - "MapDecidedInfoMessage" - { - "ru" "Итак, была выбрана карта:" - } - "MapIsInfoMessage" - { - "ru" "Карта {1}: {GREEN}{2}" - } - "TeamPickedMapInfoMessage" - { - "ru" "{1} выбрал {GREEN}{2} {NORMAL}как карту {3}" - } - "TeamSelectSideInfoMessage" - { - "ru" "{1} выбрали начать за {GREEN}{2} {NORMAL}на {3}" - } - "TeamVetoedMapInfoMessage" - { - "ru" "{1} вычеркнули {LIGHT_RED}{2}" - } - "CaptainLeftOnVetoInfoMessage" - { - "ru" "Капитан пропал по время голосования, голосование приостановлено." - } - "ReadyToResumeVetoInfoMessage" - { - "ru" "Напишите {GREEN}!ready {NORMAL}, когда будете готовы продолжить голосование." - } - "MatchConfigLoadedInfoMessage" - { - "ru" "Загружен конфиг для матча." - } - "MoveToCoachInfoMessage" - { - "ru" "Так как твоя команда заполнена, ты был перемещен на позицию тренера." - } -}