From 08902e4afa5cbb873cdf5f0371e6adef1c9711ec Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 12:55:42 +0200 Subject: [PATCH 01/34] Add previous versions to CHANGELOG --- CHANGELOG.md | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9cc7c..f7f1f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,7 +106,7 @@ All notable changes to this project will be documented in this file. This projec * Various minor bug fixes -## [1.8.0] - 2017-10-23 +## [1.8.0] - 2016-10-23 ### Added * Added support of bot commands in rotating messages: `@admins`, `@nextmap` and `@time` * Added command `!rain ` to enable/disable raindrops in maps @@ -129,7 +129,47 @@ All notable changes to this project will be documented in this file. This projec * Various minor bug fixes +## [1.7.0] - 2016-10-02 +### Added +* Added full support for Urban Terror release 4.3 +* Added command `!locate` to display geolocation info of a player +* Added first knife kill message +* Added more warning reasons + +### Changed +* Improved some feedback messages +* Imported latest GeoIP database + + +## [1.6.0] - 2016-04-03 +### Added +* Added option to display headshot hit series +* Added option to display nade kill series +* Added option to display knife kill series +* Added command `!knife` to display number of knife kills +* Added most knife kills to Awards output +* Added output of message 'added to group' +* Added output of capture count as server msg in CTF mode +* Added PyPi support + +### Changed +* Consolidated warnings in one list +* Improved error message for missing games.log file +* Imported latest GeoIP database +* Performance improvements + +### Fixed +* Fixed #31: tell command suppports all player numbers +* Fixed chat message issue with single "!" content +* Fixed possible loop if games.log file is empty +* Fixed missing reason in database for command `!tb` +* Fixed missing text color setup +* Various minor bug fixes + + [Unreleased]: https://github.com/SpunkyBot/spunkybot/compare/1.10.0...HEAD [1.10.0]: https://github.com/SpunkyBot/spunkybot/compare/1.9.0...1.10.0 [1.9.0]: https://github.com/SpunkyBot/spunkybot/compare/1.8.0...1.9.0 [1.8.0]: https://github.com/SpunkyBot/spunkybot/compare/1.7.0...1.8.0 +[1.7.0]: https://github.com/SpunkyBot/spunkybot/compare/1.6.0...1.7.0 +[1.6.0]: https://github.com/SpunkyBot/spunkybot/compare/1.5.0...1.6.0 From 63972dd8cb20d46c67cec117350e4d9ac967f201 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:05:50 +0200 Subject: [PATCH 02/34] Set Unix line endings --- debian/rules | 11 +---------- systemd-spunkybot.service | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/debian/rules b/debian/rules index 410dfd1..433055b 100644 --- a/debian/rules +++ b/debian/rules @@ -1,10 +1 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# GNU copyright 1997 to 1999 by Joey Hess. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -%: - dh $@ --with python2 +#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ --with python2 \ No newline at end of file diff --git a/systemd-spunkybot.service b/systemd-spunkybot.service index d16f1bb..89bda7a 100644 --- a/systemd-spunkybot.service +++ b/systemd-spunkybot.service @@ -18,4 +18,4 @@ Type=simple Restart=always [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target From 9bd65595d23f6b388f3a87a56e6eb8395aeed1c8 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:07:38 +0200 Subject: [PATCH 03/34] Updated copyright year --- lib/MIT_LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/MIT_LICENSE b/lib/MIT_LICENSE index b19267a..1129d6f 100644 --- a/lib/MIT_LICENSE +++ b/lib/MIT_LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2017 Spunky Bot contributors +Copyright (c) 2013-2018 Spunky Bot contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From d19b555b51216f9bb0bce101f062e2a253c83011 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:11:32 +0200 Subject: [PATCH 04/34] Removed zip file for pypi sdist generation --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 1bf8d81..060ed64 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,7 @@ license-file = LICENSE ignore = E402, E501, E722 [sdist] -formats = gztar, zip +formats = gztar [bdist_wheel] python-tag = py27 From 0e8161ab472668d1fe196da7a9bdc3552dd205ad Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:12:22 +0200 Subject: [PATCH 05/34] Changed to https links --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index a0ce22d..0e3952f 100644 --- a/setup.py +++ b/setup.py @@ -56,10 +56,10 @@ See the Homepage_ for usage and documentation or visit the Git Repository_ for the source code. -.. _Spunky Bot: http://spunkybot.de/ +.. _Spunky Bot: https://spunkybot.de/ .. _Urban Terror: http://www.urbanterror.info/ -.. _MIT: http://opensource.org/licenses/MIT -.. _Homepage: http://spunkybot.de/ +.. _MIT: https://opensource.org/licenses/MIT +.. _Homepage: https://spunkybot.de/ .. _Repository: https://github.com/spunkybot/spunkybot/ """ @@ -69,9 +69,9 @@ long_description=long_description, author='Alexander Kress', author_email='feedback@spunkybot.de', - url='http://spunkybot.de/', + url='https://spunkybot.de/', keywords='Urban Terror Game Administration RCON Bot', - download_url='http://github.com/spunkybot/spunkybot/tarball/master', + download_url='https://github.com/spunkybot/spunkybot/tarball/master', license='MIT', install_requires=['setuptools'], py_modules=['spunky'], From 70768d4eace3455f1cada08d69ef6b2465973c4e Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:13:14 +0200 Subject: [PATCH 06/34] Include only specific doc files --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 3128dbd..2e9b71c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ include README.md LICENSE include lib/GeoIP.dat +include doc/Commands.md recursive-include conf *.conf -recursive-include doc *.md include debian-startscript include systemd-spunkybot.service exclude MANIFEST.in From 8180b1ea31d4cc0a8c228883163186d4d8557fa0 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:16:06 +0200 Subject: [PATCH 07/34] Fix line endings from Mac to Unix --- debian/rules | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 433055b..410dfd1 100644 --- a/debian/rules +++ b/debian/rules @@ -1 +1,10 @@ -#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ --with python2 \ No newline at end of file +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +%: + dh $@ --with python2 From e40277776c1b022f3b3b0de058888e77d468739b Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 3 Jun 2018 13:20:40 +0200 Subject: [PATCH 08/34] Ignore checksum files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index b20d84e..72e47b8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,10 @@ spunkybot.egg-info *.tar.gz *.zip *.asc +*.sig *.deb +SHASUMS +MD5SUMS # SVN .svn/ From 1a6790c3e5da0b2b0923974d03e1094b84ccbe71 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:08:27 +0200 Subject: [PATCH 09/34] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d368c4e..b41beba 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ If you want to know more, this is a list of selected starting points: ## Environment -- Urban Terror 4.1.1 / 4.2.023 / 4.3.3 +- Urban Terror 4.1.1 / 4.2.023 / 4.3.4 - Python 2.6 / 2.7 - SQLite 3 database - Cross-platform (tested on Debian 6 / 7 / 8 / 9, Ubuntu 12 / 14 / 16 / 18, CentOS 6 / 7, macOS 10.13, Windows 7 / 10) From 885497975e46c3fac10035b496cfe738b3807dc5 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:13:45 +0200 Subject: [PATCH 10/34] Fix version check, issued by string compare --- spunky.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index 6dd62b5..da7d8b0 100644 --- a/spunky.py +++ b/spunky.py @@ -2107,11 +2107,17 @@ def handle_say(self, line): # version - display the version of the bot elif sar['command'] == '!version' and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['version']['level']: self.game.rcon_tell(sar['player_num'], "^7Spunky Bot ^2v%s" % __version__) + current = __version__.split('.') try: get_latest = urllib2.urlopen('https://raw.githubusercontent.com/SpunkyBot/spunkybot/master/VERSION', timeout=3).read().strip() except urllib2.URLError: get_latest = __version__ - if __version__ < get_latest: + latest = get_latest.split('.') + if int(current[0]) < int(latest[0]): + self.game.rcon_tell(sar['player_num'], "^7A newer release ^6%s ^7is available, check ^3www.spunkybot.de" % get_latest) + elif int(current[0]) == int(latest[0]) and int(current[1]) < int(latest[1]): + self.game.rcon_tell(sar['player_num'], "^7A newer release ^6%s ^7is available, check ^3www.spunkybot.de" % get_latest) + elif int(current[0]) == int(latest[0]) and int(current[1]) == int(latest[1]) and int(current[2]) < int(latest[2]): self.game.rcon_tell(sar['player_num'], "^7A newer release ^6%s ^7is available, check ^3www.spunkybot.de" % get_latest) # veto - stop voting process From 0c0dc4d81a93b5f2ee34d8226e32c34970cb35ad Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:19:55 +0200 Subject: [PATCH 11/34] Add command banall to ban all players matching pattern --- doc/Commands.md | 3 +++ doc/commands.html | 7 ++++++- spunky.py | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/Commands.md b/doc/Commands.md index 24a265f..e79d6a1 100644 --- a/doc/Commands.md +++ b/doc/Commands.md @@ -185,6 +185,9 @@ - **addbots** - add bots to the game - Usage: `!addbots` +- **banall** - ban all players matching pattern + - Usage: `!banall []` + - Short: `!ball` - **banlist** - display the last active 10 bans - Usage: `!banlist` - **bots** - enables or disables bot support diff --git a/doc/commands.html b/doc/commands.html index 38ce4d1..9827f5a 100644 --- a/doc/commands.html +++ b/doc/commands.html @@ -333,6 +333,11 @@

Senior Admin [80]

  • Usage: !addbots
  • +
  • banall - ban all players matching pattern
      +
    • Usage: !banall <pattern> [<reason>]
    • +
    • Short: !ball
    • +
    +
  • banlist - display the last active 10 bans
    • Usage: !banlist
    @@ -493,4 +498,4 @@

    Head Admin [100]

    - \ No newline at end of file + diff --git a/spunky.py b/spunky.py index da7d8b0..8627a4d 100644 --- a/spunky.py +++ b/spunky.py @@ -129,6 +129,7 @@ 'veto': {'desc': 'stop voting process', 'syntax': '^7Usage: ^2!veto', 'level': 60}, # senioradmin commands, level 80 'addbots': {'desc': 'add bots to the game', 'syntax': '^7Usage: ^2!addbots', 'level': 80}, + 'banall': {'desc': 'ban all players matching pattern', 'syntax': '^7Usage: ^2!banall ^7 []', 'level': 80, 'short': 'ball'}, 'banlist': {'desc': 'display the last active 10 bans', 'syntax': '^7Usage: ^2!banlist', 'level': 80}, 'bots': {'desc': 'enables or disables bot support', 'syntax': '^7Usage: ^2!bots ^7', 'level': 80}, 'cyclemap': {'desc': 'cycle to the next map', 'syntax': '^7Usage: ^2!cyclemap', 'level': 80}, @@ -2238,6 +2239,28 @@ def handle_say(self, line): else: self.game.rcon_tell(sar['player_num'], COMMANDS['kickall']['syntax']) + # !banall []- ban all players matching + elif (sar['command'] == '!banall' or sar['command'] == '!ball') and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['banall']['level']: + if line.split(sar['command'])[1]: + arg = line.split(sar['command'])[1].split() + user = arg[0] + reason = ' '.join(arg[1:])[:40].strip() if len(arg) > 1 else 'tempban' + if len(user) > 2: + pattern_list = [player for player in self.game.players.itervalues() if user.upper() in player.get_name().upper() and player.get_player_num() != BOT_PLAYER_NUM] + if pattern_list: + for player in pattern_list: + if player.get_admin_role() >= self.game.players[sar['player_num']].get_admin_role(): + self.game.rcon_tell(sar['player_num'], "^3Insufficient privileges to ban an admin") + else: + player.ban(duration=(self.ban_duration * 86400), reason=reason, admin=self.game.players[sar['player_num']].get_name()) + self.game.rcon_say("^2%s ^1banned ^7for ^3%d day%s ^7by %s" % (player.get_name(), self.ban_duration, 's' if self.ban_duration > 1 else '', self.game.players[sar['player_num']].get_name())) + else: + self.game.rcon_tell(sar['player_num'], "^3No Players found matching %s" % user) + else: + self.game.rcon_tell(sar['player_num'], "^3Pattern must be at least 3 characters long") + else: + self.game.rcon_tell(sar['player_num'], COMMANDS['banall']['syntax']) + # !addbots elif sar['command'] == '!addbots' and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['addbots']['level']: self.game.send_rcon('addbot boa 3 blue 50 BOT1') @@ -2253,6 +2276,7 @@ def handle_say(self, line): self.game.send_rcon('bot_enable 1') self.game.send_rcon('bot_minplayers 0') self.game.rcon_tell(sar['player_num'], "^7Bot support: ^2On") + self.game.rcon_tell(sar['player_num'], "^3Note: Map cycle may needed to activate bot support") elif arg == "off": self.game.send_rcon('bot_enable 0') self.game.send_rcon('kick allbots') From e79ac03840cb6e01615ff50742a23b2b3118641f Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:22:19 +0200 Subject: [PATCH 12/34] Exclude World/Bot from list of players to kick if pattern matches --- spunky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index 8627a4d..04ba530 100644 --- a/spunky.py +++ b/spunky.py @@ -2225,7 +2225,7 @@ def handle_say(self, line): user = arg[0] reason = ' '.join(arg[1:])[:40].strip() if len(arg) > 1 else '' if len(user) > 2: - pattern_list = [player for player in self.game.players.itervalues() if user.upper() in player.get_name().upper()] + pattern_list = [player for player in self.game.players.itervalues() if user.upper() in player.get_name().upper() and player.get_player_num() != BOT_PLAYER_NUM] if pattern_list: for player in pattern_list: if player.get_admin_role() >= self.game.players[sar['player_num']].get_admin_role(): From 5eb7cc1e84e9ebc4494c21bb035221b5fef05491 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:24:34 +0200 Subject: [PATCH 13/34] Improve help output of command kickall --- spunky.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spunky.py b/spunky.py index 04ba530..1c506f2 100644 --- a/spunky.py +++ b/spunky.py @@ -2233,9 +2233,9 @@ def handle_say(self, line): else: self.game.kick_player(player.get_player_num(), reason) else: - self.game.rcon_say("^3No Players found matching %s" % user) + self.game.rcon_tell(sar['player_num'], "^3No Players found matching %s" % user) else: - self.game.rcon_say("^3Pattern must be at least 3 characters long") + self.game.rcon_tell(sar['player_num'], "^3Pattern must be at least 3 characters long") else: self.game.rcon_tell(sar['player_num'], COMMANDS['kickall']['syntax']) From 01d2238cc599b543b00c2d7aa4701c1142c5653d Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:26:28 +0200 Subject: [PATCH 14/34] Exclude bots from autokick of low score players to avoid unbalanced teams --- spunky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index 1c506f2..d0bcc82 100644 --- a/spunky.py +++ b/spunky.py @@ -609,7 +609,7 @@ def taskmanager(self): player.clear_specific_warning('spectator too long on full server') # check for players with low score and set warning - if self.noob_autokick and player_admin_role < 2: + if self.noob_autokick and player_admin_role < 2 and player.get_ip_address() != '0.0.0.0': kills = player.get_kills() deaths = player.get_deaths() ratio = round(float(kills) / float(deaths), 2) if deaths > 0 else 1.0 From 4ede92db3dc945ca1af3dc508ff4fc0d9018c4cc Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:27:10 +0200 Subject: [PATCH 15/34] Exclude bots from autokick for team kills to avoid unbalanced teams --- spunky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index d0bcc82..c1fe770 100644 --- a/spunky.py +++ b/spunky.py @@ -1047,7 +1047,7 @@ def handle_kill(self, line): # increase team death counter for victim victim.team_death() # Regular and higher will not get punished - if killer.get_admin_role() < 2 and self.tk_autokick: + if killer.get_admin_role() < 2 and self.tk_autokick and killer.get_ip_address() != '0.0.0.0': # list of players of TK victim killer.add_tk_victims(victim_id) # list of players who killed victim From 25352809348de5ac4bea04b542be170ae56d32cf Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:30:05 +0200 Subject: [PATCH 16/34] Fix #55: no spawnkill autokick for bots --- spunky.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spunky.py b/spunky.py index c1fe770..7b7dff1 100644 --- a/spunky.py +++ b/spunky.py @@ -1082,8 +1082,11 @@ def handle_kill(self, line): # Spawn Protection time between players deaths in seconds to issue a warning warn_time = 3 if victim.get_respawn_time() + warn_time > time.time(): - killer.add_warning("stop spawn killing") - self.kick_high_warns(killer, 'stop spawn killing', 'Spawn Camping and Spawn Killing are not allowed') + if killer.get_ip_address() != '0.0.0.0': + killer.add_warning("stop spawn killing") + self.kick_high_warns(killer, 'stop spawn killing', 'Spawn Camping and Spawn Killing are not allowed') + else: + self.game.send_rcon("smite %d" % killer_id) # multi kill message if self.show_multikill_msg: From 5a7fd85240979a3647537de802ab1181d1e57a51 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:39:55 +0200 Subject: [PATCH 17/34] Add option to kill spawnkillers instantly --- conf/settings.conf | 1 + spunky.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/conf/settings.conf b/conf/settings.conf index 60e61f2..545724f 100644 --- a/conf/settings.conf +++ b/conf/settings.conf @@ -18,6 +18,7 @@ kick_spec_full_server = 10 ; Warn / kick spectator when teamkill_autokick = 1 ; Enable (1) or disable (0) autokick for team killing. Regulars or higher levels will not get kicked. Default: 1 noob_autokick = 0 ; Enable (1) or disable (0) autokick of players with low score. Regulars or higher levels will not get kicked. Default: 0 spawnkill_autokick = 0 ; Enable (1) or disable (0) autokick for spawn killing. Admins or higher levels will not get kicked. Default: 0 +instant_kill_spawnkiller = 0 ; Enable (1) or disable (0) instant kill for player doing spawn kill. Admins or higher levels will not get killed. Default: 0 bad_words_autokick = 0 ; Enable (1) or disable (0) autokick for using bad words. Admins or higher levels will not get kicked. Default: 0 show_country_on_connect = 1 ; Enable (1) or disable (0) displaying message "Player connected from...". Default: 1 show_first_kill = 1 ; Enable (1) or disable (0) displaying message "firstblood" / "first nade kill". Default: 1 diff --git a/spunky.py b/spunky.py index c1fe770..cbd01d9 100644 --- a/spunky.py +++ b/spunky.py @@ -316,6 +316,7 @@ def __init__(self, config_file): # enable/disable autokick of players with low score self.noob_autokick = config.getboolean('bot', 'noob_autokick') if config.has_option('bot', 'noob_autokick') else False self.spawnkill_autokick = config.getboolean('bot', 'spawnkill_autokick') if config.has_option('bot', 'spawnkill_autokick') else False + self.kill_spawnkiller = config.getboolean('bot', 'instant_kill_spawnkiller') if config.has_option('bot', 'instant_kill_spawnkiller') else False # set the maximum allowed ping self.max_ping = config.getint('bot', 'max_ping') if config.has_option('bot', 'max_ping') else 200 # kick spectator on full server @@ -1077,13 +1078,20 @@ def handle_kill(self, line): elif not tk_event and int(info[2]) != 10: # 10: MOD_CHANGE_TEAM killer.kill() - # spawn kill warning - if self.spawnkill_autokick and killer.get_admin_role() < 40: + # spawn killing - warn/kick or instant kill + if (self.spawnkill_autokick or self.kill_spawnkiller) and killer.get_admin_role() < 40: # Spawn Protection time between players deaths in seconds to issue a warning warn_time = 3 if victim.get_respawn_time() + warn_time > time.time(): - killer.add_warning("stop spawn killing") - self.kick_high_warns(killer, 'stop spawn killing', 'Spawn Camping and Spawn Killing are not allowed') + if killer.get_ip_address() != '0.0.0.0': + if self.kill_spawnkiller: + self.game.send_rcon("smite %d" % killer_id) + self.game.rcon_say("^7%s got killed for Spawn Killing", killer_id) + if self.spawnkill_autokick: + killer.add_warning("stop spawn killing") + self.kick_high_warns(killer, 'stop spawn killing', 'Spawn Camping and Spawn Killing are not allowed') + else: + self.game.send_rcon("smite %d" % killer_id) # multi kill message if self.show_multikill_msg: From 529e944b9d363481b77602d7202267c7f8c03ae0 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 30 Jun 2018 12:56:34 +0200 Subject: [PATCH 18/34] Improve notice for enabling bot support --- spunky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index cbd01d9..77dda46 100644 --- a/spunky.py +++ b/spunky.py @@ -2284,7 +2284,7 @@ def handle_say(self, line): self.game.send_rcon('bot_enable 1') self.game.send_rcon('bot_minplayers 0') self.game.rcon_tell(sar['player_num'], "^7Bot support: ^2On") - self.game.rcon_tell(sar['player_num'], "^3Note: Map cycle may needed to activate bot support") + self.game.rcon_tell(sar['player_num'], "^3Map cycle may be required to enable bot support") elif arg == "off": self.game.send_rcon('bot_enable 0') self.game.send_rcon('kick allbots') From 8ccfbcc867624b0d960293dca2c10e9433e17a9f Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 15 Jul 2018 19:18:52 +0200 Subject: [PATCH 19/34] Fix #56: not all maps are shown/listed --- spunky.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/spunky.py b/spunky.py index 77dda46..1025832 100644 --- a/spunky.py +++ b/spunky.py @@ -3973,15 +3973,20 @@ def set_all_maps(self): set a list of all available maps """ try: - all_maps = self.get_rcon_output("dir map bsp")[1].split() - all_maps_list = [maps.replace("/", "").replace(".bsp", "") for maps in all_maps if maps.startswith("/")] - pk3_list = self.get_rcon_output("fdir *.pk3")[1].split() - all_pk3_list = [maps.replace("/", "").replace(".pk3", "").replace(".bsp", "") for maps in pk3_list if maps.startswith("/ut4_") or maps.startswith("/ut_")] - - all_together = list(set(all_maps_list + all_pk3_list)) - all_together.sort() - if all_together: - self.all_maps_list = all_together + all_maps = [] + count = 0 + while True: + ret_val = self.get_rcon_output("dir map bsp")[1].split() + if "Directory" in ret_val: + count += 1 + if count >= 2: + break + else: + all_maps += ret_val + all_maps_list = list(set([maps.replace("/", "").replace(".bsp", "") for maps in all_maps if maps.startswith("/")])) + all_maps_list.sort() + if all_maps_list: + self.all_maps_list = all_maps_list except Exception as err: logger.error(err, exc_info=True) From 4352d23dfd83f11a03f81c77ea3dbe871290fe1c Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 15 Jul 2018 19:22:23 +0200 Subject: [PATCH 20/34] Show number of available maps for command \!maps --- spunky.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index 1025832..e508319 100644 --- a/spunky.py +++ b/spunky.py @@ -2328,7 +2328,8 @@ def handle_say(self, line): # maps - display all available maps elif (sar['command'] == '!maps' or sar['command'] == '@maps') and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['maps']['level']: - msg = "^7Available Maps: ^3%s" % ', ^3'.join(self.game.get_all_maps()) + map_list = self.game.get_all_maps() + msg = "^7Available Maps [^2%s^7]: ^3%s" % (len(map_list), ', ^3'.join(map_list)) self.tell_say_message(sar, msg) # maprestart - restart the map From a5d57b2fdc8a8f9ce2628cf78c241d24597cc521 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 15 Jul 2018 19:22:23 +0200 Subject: [PATCH 21/34] Show number of available maps for command !maps --- spunky.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index 1025832..e508319 100644 --- a/spunky.py +++ b/spunky.py @@ -2328,7 +2328,8 @@ def handle_say(self, line): # maps - display all available maps elif (sar['command'] == '!maps' or sar['command'] == '@maps') and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['maps']['level']: - msg = "^7Available Maps: ^3%s" % ', ^3'.join(self.game.get_all_maps()) + map_list = self.game.get_all_maps() + msg = "^7Available Maps [^2%s^7]: ^3%s" % (len(map_list), ', ^3'.join(map_list)) self.tell_say_message(sar, msg) # maprestart - restart the map From b345cad2bad722e97589c2c663e92c457e01d240 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 15 Jul 2018 19:29:21 +0200 Subject: [PATCH 22/34] Set link to develop branch --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f1f66..6c0776f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -167,7 +167,7 @@ All notable changes to this project will be documented in this file. This projec * Various minor bug fixes -[Unreleased]: https://github.com/SpunkyBot/spunkybot/compare/1.10.0...HEAD +[Unreleased]: https://github.com/SpunkyBot/spunkybot/compare/1.10.0...develop [1.10.0]: https://github.com/SpunkyBot/spunkybot/compare/1.9.0...1.10.0 [1.9.0]: https://github.com/SpunkyBot/spunkybot/compare/1.8.0...1.9.0 [1.8.0]: https://github.com/SpunkyBot/spunkybot/compare/1.7.0...1.8.0 From 12e36ef3402914106f22aff4bbb78c509da41d5c Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 22 Jul 2018 10:30:54 +0200 Subject: [PATCH 23/34] Show total number of maps in devel.log file --- spunky.py | 1 + 1 file changed, 1 insertion(+) diff --git a/spunky.py b/spunky.py index e508319..ff7f403 100644 --- a/spunky.py +++ b/spunky.py @@ -3933,6 +3933,7 @@ def go_live(self): self.rcon_say("^7Powered by ^8[Spunky Bot %s] ^1[www.spunkybot.de]" % __version__) logger.info("Mapcycle: %s", ', '.join(self.maplist)) logger.info("*** Live tracking: Current map: %s / Next map: %s ***", self.mapname, self.next_mapname) + logger.info("Total number of maps : %s", len(self.get_all_maps())) logger.info("Server CVAR g_logsync : %s", self.get_cvar('g_logsync')) logger.info("Server CVAR g_loghits : %s", self.get_cvar('g_loghits')) From cfaf68a34699763f9b818c7a257d4c17261806cb Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 22 Jul 2018 10:37:07 +0200 Subject: [PATCH 24/34] Fix #57: year 2038 problem on 32-bit systems --- spunky.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spunky.py b/spunky.py index ff7f403..8ba9035 100644 --- a/spunky.py +++ b/spunky.py @@ -3156,8 +3156,10 @@ def __init__(self, player_num, ip_address, guid, name, auth=''): def ban(self, duration=900, reason='tk', admin=None): if admin: reason = "%s, ban by %s" % (reason, admin) - unix_expiration = duration + time.time() - expire_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(unix_expiration)) + try: + expire_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time() + duration)) + except ValueError: + expire_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(2147483647)) timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) values = (self.guid,) curs.execute("SELECT `expires` FROM `ban_list` WHERE `guid` = ?", values) @@ -3180,8 +3182,10 @@ def ban(self, duration=900, reason='tk', admin=None): return True def add_ban_point(self, point_type, duration): - unix_expiration = duration + time.time() - expire_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(unix_expiration)) + try: + expire_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time() + duration)) + except ValueError: + expire_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(2147483647)) values = (self.guid, point_type, expire_date) # add ban_point to database curs.execute("INSERT INTO `ban_points` (`guid`,`point_type`,`expires`) VALUES (?,?,?)", values) From a3ce6aa0106c2ef429d55fa6d2aadaa650211510 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 4 Aug 2018 12:03:04 +0200 Subject: [PATCH 25/34] Use a function to count online players --- spunky.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/spunky.py b/spunky.py index 8ba9035..eeac8ff 100644 --- a/spunky.py +++ b/spunky.py @@ -560,7 +560,7 @@ def taskmanager(self): try: with self.players_lock: # get number of connected players - counter = len(self.game.players) - 1 # bot is counted as player + counter = self.game.get_number_players() # check amount of warnings and kick player if needed for player in self.game.players.itervalues(): @@ -3802,6 +3802,12 @@ def get_cvar(self, value): time.sleep(RCON_DELAY) return ret_val + def get_number_players(self): + """ + get the number of online players + """ + return len(self.players) - 1 # bot is counted as player + def get_mapcycle_path(self): """ get the full path of mapcycle.txt file @@ -3953,8 +3959,8 @@ def set_current_map(self): self.mapname = self.next_mapname if self.dynamic_mapcycle: - self.maplist = filter(None, (self.small_cycle if len(self.players) < (self.switch_count + 1) else self.big_cycle)) - logger.debug("Players online: %s / Mapcycle: %s", (len(self.players) - 1), self.maplist) + self.maplist = filter(None, (self.small_cycle if self.get_number_players() < self.switch_count else self.big_cycle)) + logger.debug("Players online: %s / Mapcycle: %s", self.get_number_players(), self.maplist) if self.maplist: if self.mapname in self.maplist: From 3424939a1058413f8f27a3ad5a631c9893589e9a Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sat, 4 Aug 2018 12:08:29 +0200 Subject: [PATCH 26/34] Ignore team kill event in case team is not set or spec --- spunky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index eeac8ff..d90d5a9 100644 --- a/spunky.py +++ b/spunky.py @@ -1041,7 +1041,7 @@ def handle_kill(self, line): # teamkill event - disabled for FFA, LMS, Jump, for all other game modes team kills are counted and punished if not self.ffa_lms_gametype: - if (victim.get_team() == killer.get_team() and victim_id != killer_id) and death_cause != "UT_MOD_BOMBED": + if victim.get_team() == killer.get_team() and victim.get_team() != 3 and victim_id != killer_id and death_cause != "UT_MOD_BOMBED": tk_event = True # increase team kill counter for killer and kick for too many team kills killer.team_kill() From 4b4bb54d1b35222a4dae88f0e6ca4296cd04c7eb Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 5 Aug 2018 11:43:44 +0200 Subject: [PATCH 27/34] Updated description since ban interval can be configured --- spunky.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spunky.py b/spunky.py index d90d5a9..b16c5ee 100644 --- a/spunky.py +++ b/spunky.py @@ -113,7 +113,7 @@ 'tempban': {'desc': 'ban a player temporary for the given period', 'syntax': '^7Usage: ^2!tempban ^7 []', 'level': 40, 'short': 'tb'}, 'warnclear': {'desc': 'clear the player warnings', 'syntax': '^7Usage: ^2!warnclear ^7', 'level': 40, 'short': 'wc'}, # fulladmin commands, level 60 - 'ban': {'desc': 'ban a player for 7 days', 'syntax': '^7Usage: ^2!ban ^7 ', 'level': 60, 'short': 'b'}, + 'ban': {'desc': 'ban a player for several days', 'syntax': '^7Usage: ^2!ban ^7 ', 'level': 60, 'short': 'b'}, 'baninfo': {'desc': 'display active bans of a player', 'syntax': '^7Usage: ^2!baninfo ^7', 'level': 60, 'short': 'bi'}, 'ci': {'desc': 'kick player with connection interrupt', 'syntax': '^7Usage: ^2!ci ^7', 'level': 60}, 'forgiveclear': {'desc': "clear a player's team kills", 'syntax': '^7Usage: ^2!forgiveclear ^7[]', 'level': 60, 'short': 'fc'}, @@ -2155,7 +2155,7 @@ def handle_say(self, line): else: self.game.rcon_tell(sar['player_num'], COMMANDS['ci']['syntax']) - # ban - ban a player for 7 days + # ban - ban a player for several days elif (sar['command'] == '!ban' or sar['command'] == '!b') and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['ban']['level']: if line.split(sar['command'])[1]: arg = line.split(sar['command'])[1].split() From b4906e368f09a9f81bcaf9636024eb5ded59abf0 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 5 Aug 2018 11:49:32 +0200 Subject: [PATCH 28/34] Added command !rebuild to sync up all available maps --- doc/Commands.md | 2 ++ doc/commands.html | 4 ++++ spunky.py | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/doc/Commands.md b/doc/Commands.md index e79d6a1..cee0519 100644 --- a/doc/Commands.md +++ b/doc/Commands.md @@ -232,6 +232,8 @@ - **putgroup** - add a client to a group - Usage: `!putgroup ` - Available Groups: _user_, _regular_, _mod_, _admin_, _fulladmin_ +- **rebuild** - sync up all available maps + - Usage: `!rebuild` - **setnextmap** - set the next map - Usage: `!setnextmap ` - **swapteams** - swap the current teams diff --git a/doc/commands.html b/doc/commands.html index 9827f5a..4408232 100644 --- a/doc/commands.html +++ b/doc/commands.html @@ -418,6 +418,10 @@

    Senior Admin [80]

  • Available Groups: user, regular, mod, admin, fulladmin
  • +
  • rebuild - sync up all available maps
      +
    • Usage: !rebuild
    • +
    +
  • setnextmap - set the next map
    • Usage: !setnextmap <ut4_name>
    diff --git a/spunky.py b/spunky.py index b16c5ee..71fbd63 100644 --- a/spunky.py +++ b/spunky.py @@ -148,6 +148,7 @@ 'moon': {'desc': 'activate Moon mode (low gravity)', 'syntax': '^7Usage: ^2!moon ^7', 'level': 80}, 'permban': {'desc': 'ban a player permanent', 'syntax': '^7Usage: ^2!permban ^7 ', 'level': 80, 'short': 'pb'}, 'putgroup': {'desc': 'add a client to a group', 'syntax': '^7Usage: ^2!putgroup ^7 ', 'level': 80}, + 'rebuild': {'desc': 'sync up all available maps', 'syntax': '^7Usage: ^2!rebuild', 'level': 80}, 'setnextmap': {'desc': 'set the next map', 'syntax': '^7Usage: ^2!setnextmap ^7', 'level': 80}, 'swapteams': {'desc': 'swap the current teams', 'syntax': '^7Usage: ^2!swapteams', 'level': 80}, 'unban': {'desc': 'unban a player from the database', 'syntax': '^7Usage: ^2!unban ^7<@ID>', 'level': 80}, @@ -2389,6 +2390,15 @@ def handle_say(self, line): else: self.game.rcon_tell(sar['player_num'], COMMANDS['setnextmap']['syntax']) + # rebuild - sync up all available maps + elif sar['command'] == '!rebuild' and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['rebuild']['level']: + # get full map list + self.game.set_all_maps() + self.game.rcon_tell(sar['player_num'], "^7Rebuild maps: ^3%s ^7maps found" % len(self.game.get_all_maps())) + # set current and next map + self.game.set_current_map() + self.game.rcon_tell(sar['player_num'], self.get_nextmap()) + # swapteams - swap current teams elif sar['command'] == '!swapteams' and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['swapteams']['level']: self.game.send_rcon('swapteams') From 911b5ca976fde50491bc125c026c7776775a0d47 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 5 Aug 2018 12:22:45 +0200 Subject: [PATCH 29/34] Bumped version number to 1.11.0 --- README.md | 2 +- VERSION | 2 +- debian/control | 2 +- spunky.py | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b41beba..82cc172 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The code of Spunky Bot is inspired by the eb2k9 bot by Shawn Haggard, which was [![Build Status](https://travis-ci.org/SpunkyBot/spunkybot.png?branch=master)](https://travis-ci.org/SpunkyBot/spunkybot) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/SpunkyBot/spunkybot/blob/master/LICENSE) -[![Version](https://img.shields.io/badge/version-1.10.0-orange.svg)](https://github.com/SpunkyBot/spunkybot/releases) +[![Version](https://img.shields.io/badge/version-1.11.0-orange.svg)](https://github.com/SpunkyBot/spunkybot/releases) [![PyPI version](https://img.shields.io/pypi/v/spunkybot.svg)](https://pypi.python.org/pypi/spunkybot) [![Python version](https://img.shields.io/badge/python-2.6,%202.7-yellow.svg)](https://pypi.python.org/pypi/spunkybot) [![Code Health](https://landscape.io/github/SpunkyBot/spunkybot/master/landscape.svg)](https://landscape.io/github/SpunkyBot/spunkybot/master) diff --git a/VERSION b/VERSION index 81c871d..1cac385 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.0 +1.11.0 diff --git a/debian/control b/debian/control index 7c35fe9..b49af66 100644 --- a/debian/control +++ b/debian/control @@ -1,5 +1,5 @@ Package: spunkybot -Version: 1.10.0 +Version: 1.11.0 Section: utils Priority: optional Architecture: all diff --git a/spunky.py b/spunky.py index 71fbd63..64ca5dc 100644 --- a/spunky.py +++ b/spunky.py @@ -22,7 +22,7 @@ Run the bot: python spunky.py """ -__version__ = '1.10.0' +__version__ = '1.11.0' ### IMPORTS @@ -288,7 +288,7 @@ def __init__(self, config_file): logger.addHandler(console) logger.addHandler(devel_log) - logger.info("*** Spunky Bot v%s : www.spunkybot.de ***", __version__) + logger.info("*** Spunky Bot v%s : www.spunkybot.de ***", __version__ = '1.11.0' logger.info("Starting logging : OK") logger.info("Loading config file : %s", config_file) @@ -355,7 +355,7 @@ def __init__(self, config_file): logger.debug("Cmd !iamgod available : %s", self.iamgod) server_port = config.get('server', 'server_port') if config.has_option('server', 'server_port') else "27960" # Heartbeat packet - data = {'v': __version__, 'p': server_port, 'o': platform.platform()} + data = {'v': __version__ = '1.11.0' self.heartbeat = config.getboolean('bot', 'heartbeat') if config.has_option('bot', 'heartbeat') else False # Master Server self.ping_url = 'http://master.spunkybot.de/ping.php?%s' % urllib.urlencode(data) @@ -2116,12 +2116,12 @@ def handle_say(self, line): # version - display the version of the bot elif sar['command'] == '!version' and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['version']['level']: - self.game.rcon_tell(sar['player_num'], "^7Spunky Bot ^2v%s" % __version__) - current = __version__.split('.') + self.game.rcon_tell(sar['player_num'], "^7Spunky Bot ^2v%s" % __version__ = '1.11.0' + current = __version__ = '1.11.0' try: get_latest = urllib2.urlopen('https://raw.githubusercontent.com/SpunkyBot/spunkybot/master/VERSION', timeout=3).read().strip() except urllib2.URLError: - get_latest = __version__ + get_latest = __version__ = '1.11.0' latest = get_latest.split('.') if int(current[0]) < int(latest[0]): self.game.rcon_tell(sar['player_num'], "^7A newer release ^6%s ^7is available, check ^3www.spunkybot.de" % get_latest) @@ -3950,7 +3950,7 @@ def go_live(self): self.set_all_maps() self.maplist = filter(None, self.get_mapcycle_path()) self.set_current_map() - self.rcon_say("^7Powered by ^8[Spunky Bot %s] ^1[www.spunkybot.de]" % __version__) + self.rcon_say("^7Powered by ^8[Spunky Bot %s] ^1[www.spunkybot.de]" % __version__ = '1.11.0' logger.info("Mapcycle: %s", ', '.join(self.maplist)) logger.info("*** Live tracking: Current map: %s / Next map: %s ***", self.mapname, self.next_mapname) logger.info("Total number of maps : %s", len(self.get_all_maps())) From 66e17af1e98880bf30e42aaa2c3ba5fdad32e8a0 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 5 Aug 2018 12:43:58 +0200 Subject: [PATCH 30/34] Fixed sed command which broke __version__ string update --- spunky.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spunky.py b/spunky.py index 64ca5dc..728e40d 100644 --- a/spunky.py +++ b/spunky.py @@ -288,7 +288,7 @@ def __init__(self, config_file): logger.addHandler(console) logger.addHandler(devel_log) - logger.info("*** Spunky Bot v%s : www.spunkybot.de ***", __version__ = '1.11.0' + logger.info("*** Spunky Bot v%s : www.spunkybot.de ***", __version__) logger.info("Starting logging : OK") logger.info("Loading config file : %s", config_file) @@ -355,7 +355,7 @@ def __init__(self, config_file): logger.debug("Cmd !iamgod available : %s", self.iamgod) server_port = config.get('server', 'server_port') if config.has_option('server', 'server_port') else "27960" # Heartbeat packet - data = {'v': __version__ = '1.11.0' + data = {'v': __version__, 'p': server_port, 'o': platform.platform()} self.heartbeat = config.getboolean('bot', 'heartbeat') if config.has_option('bot', 'heartbeat') else False # Master Server self.ping_url = 'http://master.spunkybot.de/ping.php?%s' % urllib.urlencode(data) @@ -2116,12 +2116,12 @@ def handle_say(self, line): # version - display the version of the bot elif sar['command'] == '!version' and self.game.players[sar['player_num']].get_admin_role() >= COMMANDS['version']['level']: - self.game.rcon_tell(sar['player_num'], "^7Spunky Bot ^2v%s" % __version__ = '1.11.0' - current = __version__ = '1.11.0' + self.game.rcon_tell(sar['player_num'], "^7Spunky Bot ^2v%s" % __version__) + current = __version__.split('.') try: get_latest = urllib2.urlopen('https://raw.githubusercontent.com/SpunkyBot/spunkybot/master/VERSION', timeout=3).read().strip() except urllib2.URLError: - get_latest = __version__ = '1.11.0' + get_latest = __version__ latest = get_latest.split('.') if int(current[0]) < int(latest[0]): self.game.rcon_tell(sar['player_num'], "^7A newer release ^6%s ^7is available, check ^3www.spunkybot.de" % get_latest) @@ -3950,7 +3950,7 @@ def go_live(self): self.set_all_maps() self.maplist = filter(None, self.get_mapcycle_path()) self.set_current_map() - self.rcon_say("^7Powered by ^8[Spunky Bot %s] ^1[www.spunkybot.de]" % __version__ = '1.11.0' + self.rcon_say("^7Powered by ^8[Spunky Bot %s] ^1[www.spunkybot.de]" % __version__) logger.info("Mapcycle: %s", ', '.join(self.maplist)) logger.info("*** Live tracking: Current map: %s / Next map: %s ***", self.mapname, self.next_mapname) logger.info("Total number of maps : %s", len(self.get_all_maps())) From 9a9fd1aa82ce30f69cd5df3e7aed933344368264 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Sun, 5 Aug 2018 12:49:37 +0200 Subject: [PATCH 31/34] Updated CHANGELOG to 1.11.0 --- CHANGELOG.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0776f..5958497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] +## [1.11.0] - 2018-08-05 +### Added +* Added command `!banall ` to ban all players matching pattern +* Added command `!rebuild` to sync up all available maps +* Added option to kill spawnkillers instantly +* Added support for Urban Terror 4.3.4 + +### Changed +* Command `!maps` is showing the total number of available maps +* Exclude bots from autokick for team kills to avoid unbalanced teams +* Exclude bots from autokick of low score players to avoid unbalanced teams +* Improved some feedback messages + +### Fixed +* Fixed #55: Make bots immune from spawnkill autokick +* Fixed #56: Command `!maps` does not show all maps +* Fixed #57: Fix year 2038 problem on 32-bit systems +* Fixed version check, issued by string compare +* Various minor bug fixes + + ## [1.10.0] - 2018-05-31 ### Added * Added option for automatic expiration of warnings @@ -167,7 +188,8 @@ All notable changes to this project will be documented in this file. This projec * Various minor bug fixes -[Unreleased]: https://github.com/SpunkyBot/spunkybot/compare/1.10.0...develop +[Unreleased]: https://github.com/SpunkyBot/spunkybot/compare/1.11.0...develop +[1.11.0]: https://github.com/SpunkyBot/spunkybot/compare/1.10.0...1.11.0 [1.10.0]: https://github.com/SpunkyBot/spunkybot/compare/1.9.0...1.10.0 [1.9.0]: https://github.com/SpunkyBot/spunkybot/compare/1.8.0...1.9.0 [1.8.0]: https://github.com/SpunkyBot/spunkybot/compare/1.7.0...1.8.0 From 6d2c7d0fce09a3d46c75e4889894d24331da119a Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Mon, 6 Aug 2018 10:47:01 +0200 Subject: [PATCH 32/34] Updated schedule library to version 0.4.3 --- lib/schedule.py | 67 +++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/lib/schedule.py b/lib/schedule.py index 90b6a45..ec41451 100644 --- a/lib/schedule.py +++ b/lib/schedule.py @@ -32,9 +32,9 @@ >>> schedule.run_pending() >>> time.sleep(1) -[1] http://adam.heroku.com/past/2010/4/13/rethinking_cron/ -[2] https://github.com/tomykaira/clockwork -[3] http://adam.heroku.com/past/2010/6/30/replace_cron_with_clockwork/ +[1] https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ +[2] https://github.com/Rykian/clockwork +[3] https://adam.herokuapp.com/past/2010/6/30/replace_cron_with_clockwork/ """ import collections import datetime @@ -64,11 +64,11 @@ def run_pending(self): """ Run all jobs that are scheduled to run. - Please note that it is *intended behavior that tick() does not - run missed jobs*. For example, if you've registered a job that - should run every minute and you only call tick() in one hour - increments then your job won't be run 60 times in between but - only once. + Please note that it is *intended behavior that run_pending() + does not run missed jobs*. For example, if you've registered a job + that should run every minute and you only call run_pending() + in one hour increments then your job won't be run 60 times in + between but only once. """ runnable_jobs = (job for job in self.jobs if job.should_run) for job in sorted(runnable_jobs): @@ -160,7 +160,7 @@ class Job(object): * a quantity of `time units` defined by `interval` A job is usually created and returned by :meth:`Scheduler.every` - method, which also defines its `interval` + method, which also defines its `interval`. """ def __init__(self, interval): self.interval = interval # pause interval * unit between runs @@ -439,70 +439,49 @@ def _schedule_next_run(self): def every(interval=1): - """ - Schedule a new periodic job with the default module scheduler. - - :param interval: A quantity of any given - :meth:`time unit ` - :return: The default :obj:`Scheduler` instance + """Calls :meth:`every ` on the + :data:`default scheduler instance `. """ return default_scheduler.every(interval) def run_pending(): - """ - Run all jobs that are scheduled to run. - - Please note that it is *intended behavior that run_pending() - does not run missed jobs*. For example, if you've registered a job - that should run every minute and you only call run_pending() - in one hour increments then your job won't be run 60 times in - between but only once. + """Calls :meth:`run_pending ` on the + :data:`default scheduler instance `. """ default_scheduler.run_pending() def run_all(delay_seconds=0): - """ - Run all jobs regardless if they are scheduled to run or not. - - A delay of `delay` seconds is added between each job. This can help - to distribute the system load generated by the jobs more evenly over - time. + """Calls :meth:`run_all ` on the + :data:`default scheduler instance `. """ default_scheduler.run_all(delay_seconds=delay_seconds) def clear(tag=None): - """ - Deletes scheduled jobs on the default scheduler marked with the - given tag, or all jobs if tag is omitted - - :param tag: An identifier used to identify a subset of - jobs to delete + """Calls :meth:`clear ` on the + :data:`default scheduler instance `. """ default_scheduler.clear(tag) def cancel_job(job): - """Delete a scheduled job on the default scheduler - - :param job: The job to be unscheduled + """Calls :meth:`cancel_job ` on the + :data:`default scheduler instance `. """ default_scheduler.cancel_job(job) def next_run(): - """Datetime when the next job should run. - - :return: A :class:`~datetime.datetime` object + """Calls :meth:`next_run ` on the + :data:`default scheduler instance `. """ return default_scheduler.next_run def idle_seconds(): - """ - :return: Number of seconds until - :meth:`next_run `. + """Calls :meth:`idle_seconds ` on the + :data:`default scheduler instance `. """ return default_scheduler.idle_seconds From c62abca6ec577bc9ebab407abc45fbdd8e0d9735 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Mon, 6 Aug 2018 10:47:41 +0200 Subject: [PATCH 33/34] Updated CHANGELOG to 1.11.0 --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5958497..583d484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] -## [1.11.0] - 2018-08-05 +## [1.11.0] - 2018-08-06 ### Added * Added command `!banall ` to ban all players matching pattern * Added command `!rebuild` to sync up all available maps @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. This projec * Command `!maps` is showing the total number of available maps * Exclude bots from autokick for team kills to avoid unbalanced teams * Exclude bots from autokick of low score players to avoid unbalanced teams +* Updated schedule library * Improved some feedback messages ### Fixed From 4416846dc98cf3089497879f7b4101d2dd93ee92 Mon Sep 17 00:00:00 2001 From: Alexander Kress Date: Mon, 6 Aug 2018 14:42:38 +0200 Subject: [PATCH 34/34] Ensure that cmd !ungroup does not allow to change own group --- spunky.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spunky.py b/spunky.py index 728e40d..311b7c0 100644 --- a/spunky.py +++ b/spunky.py @@ -2652,7 +2652,7 @@ def handle_say(self, line): if not found: self.game.rcon_tell(sar['player_num'], msg) else: - if 1 < victim.get_admin_role() < 90 or self.game.players[sar['player_num']].get_admin_role() == 100: + if (1 < victim.get_admin_role() < COMMANDS['ungroup']['level'] or self.game.players[sar['player_num']].get_admin_role() == 100) and victim.get_player_num() != sar['player_num']: self.game.rcon_tell(sar['player_num'], "^1%s ^7put in group User" % victim.get_name()) victim.update_db_admin_role(role=1) else: