CTBAN with time and menu
CTBAN with time and menu
Hey guys I'm here to request a plugin that allows me to bring up a Ctban menu on !ctban command.
Re: CTBAN with time and menu
Something like this?
You need to grant yourself the permission "ctban.open":
http://wiki.sourcepython.com/general/config-auth.html
Syntax: Select all
# ==============================================================================
# >> IMPORTS
# ==============================================================================
# Python
import collections
import time
import pickle
# Source.Python
from commands.client import ClientCommandFilter
from commands.typed import TypedSayCommand
from commands import CommandReturn
from menus import PagedMenu
from menus import PagedOption
from players.entity import Player
from players.helpers import uniqueid_from_index
from players.helpers import index_from_uniqueid
from listeners import OnLevelEnd
from paths import CUSTOM_DATA_PATH
from events import Event
from filters.players import PlayerIter
from messages import SayText2
from colors import RED
# ==============================================================================
# >> CONSTANTS
# ==============================================================================
# Ban durations
DURATIONS = {
0: 'permanently',
5 * 60: '5 minutes',
15 * 60: '15 minutes',
30 * 60: '30 minutes',
60 * 60: '1 hour',
3 * 60 * 60: '3 hours',
6 * 60 * 60: '6 hours',
12 * 60 * 60: '12 hours',
24 * 60 * 60: '1 day',
3 * 24 * 60 * 60: '3 days',
7 * 24 * 60 * 60: '7 days',
}
# Path to the ban database
BAN_DATABASE = CUSTOM_DATA_PATH / 'ctban' / 'bans.db'
# Number of leavers to track
TRACKED_LEAVERS_NO = 5
# Number of freekillers to track
TRACKED_FREEKILLERS_NO = 5
# Prefix for messages
MESSAGE_PREFIX = '{}[CTBAN] \1'.format(RED)
# ==============================================================================
# >> CLASSES
# ==============================================================================
class BanSystem(dict):
def __init__(self):
self.leavers = collections.deque(maxlen=TRACKED_LEAVERS_NO)
self.freekillers = collections.deque(maxlen=TRACKED_FREEKILLERS_NO)
try:
with BAN_DATABASE.open('rb') as f:
self.update(pickle.load(f))
except FileNotFoundError:
pass
def save(self):
try:
BAN_DATABASE.parent.makedirs()
except FileExistsError:
pass
with BAN_DATABASE.open('wb') as f:
pickle.dump(self, f)
def add_ban(self, uniqueid, duration, name):
self[uniqueid] = (0 if duration == 0 else time.time() + duration, name)
try:
index = index_from_uniqueid(uniqueid)
except ValueError:
pass
else:
player = Player(index)
player.team = 2
try:
self.leavers.remove((uniqueid, name))
except ValueError:
pass
try:
self.freekillers.remove((uniqueid, name))
except ValueError:
pass
def is_banned(self, uniqueid):
try:
ban_time, name = self[uniqueid]
except KeyError:
return False
return ban_time == 0 or time.time() < ban_time
def remove_ban(self, uniqueid):
return self.pop(uniqueid, (None, None))
def cleanup(self):
now = time.time()
for uniqueid, (ban_time, name) in tuple(self.items()):
if ban_time != 0 and now >= ban_time:
del self[uniqueid]
self.save()
def track_leaver(self, uniqueid, name):
if self.is_banned(uniqueid):
return
data = (uniqueid, name)
if data not in self.leavers:
self.leavers.append(data)
def track_freekiller(self, uniqueid, name):
if self.is_banned(uniqueid):
return
data = (uniqueid, name)
if data not in self.freekillers:
self.freekillers.append(data)
ban_system = BanSystem()
# ==============================================================================
# >> BAN SYSTEM UPDATER
# ==============================================================================
@OnLevelEnd
def on_level_end():
ban_system.cleanup()
# ==============================================================================
# >> ADMIN BAN MENU
# ==============================================================================
admin_ban_menu = PagedMenu(
[
PagedOption('Ban CT', 1),
PagedOption('Ban leaver', 2),
PagedOption('Ban freekiller', 3),
PagedOption('Unban player', 4)
],
title='CTBAN'
)
@admin_ban_menu.register_select_callback
def on_admin_ban_menu_select(menu, index, option):
if option.value == 1:
return ct_menu
elif option.value == 2:
return leaver_menu
elif option.value == 3:
return freekillers_menu
elif option.value == 4:
return unban_menu
# ==============================================================================
# >> PLAYER MENU
# ==============================================================================
ct_menu = PagedMenu(
title='Ban CT',
parent_menu=admin_ban_menu)
freekillers_menu = PagedMenu(
title='Ban freekiller',
parent_menu=admin_ban_menu
)
leaver_menu = PagedMenu(
title='Ban leaver',
parent_menu=admin_ban_menu
)
@ct_menu.register_build_callback
def on_active_player_menu_build(menu, index):
menu.clear()
for player in PlayerIter(['ct']):
if player.index == index:
continue
menu.append(PagedOption(player.name, (player.uniqueid, player.name)))
@leaver_menu.register_build_callback
def on_leaver_menu_build(menu, index):
menu.clear()
for uniqueid, name in ban_system.leavers:
menu.append(PagedOption(name, (uniqueid, name)))
@freekillers_menu.register_build_callback
def on_freekillers_menu_build(menu, index):
menu.clear()
for uniqueid, name in ban_system.freekillers:
menu.append(PagedOption(name, (uniqueid, name)))
@leaver_menu.register_select_callback
@ct_menu.register_select_callback
@freekillers_menu.register_select_callback
def on_active_player_menu_select(menu, index, option):
return create_ban_time_menu(menu, *option.value)
# ==============================================================================
# >> UNBAN MENU
# ==============================================================================
unban_menu = PagedMenu(
title='Unban player',
parent_menu=admin_ban_menu)
@unban_menu.register_build_callback
def on_unban_menu_build(menu, index):
menu.clear()
bans = tuple(ban_system.items())
sorted_bans = sorted(bans, key=lambda key: key[1][1])
for uniqueid, (ban_time, name) in sorted_bans:
menu.append(PagedOption('{} ({})'.format(name, uniqueid), uniqueid))
@unban_menu.register_select_callback
def on_unban_menu_select(menu, index, option):
ban_time, name = ban_system.remove_ban(option.value)
if ban_time is not None:
SayText2(
MESSAGE_PREFIX + '{} has been unbanned from the CT team.'.format(
name)).send()
# ==============================================================================
# >> BAN TIME MENU
# ==============================================================================
def create_ban_time_menu(parent_menu, uniqueid, name):
ban_time_menu = PagedMenu(title='Ban time', parent_menu=parent_menu)
for duration, display_name in sorted(DURATIONS.items()):
ban_time_menu.append(
PagedOption(display_name, (uniqueid, name, duration)))
ban_time_menu.select_callback = on_ban_time_menu_select
return ban_time_menu
def on_ban_time_menu_select(menu, index, option):
uniqueid, name, duration = option.value
ban_system.add_ban(uniqueid, duration, name)
SayText2(
MESSAGE_PREFIX + '{} has been banned from the CT team ({}).'.format(
name, option.text)).send()
# ==============================================================================
# >> SAY COMMANDS
# ==============================================================================
@TypedSayCommand('!ctban', 'ctban.open')
def on_ctban_open(info):
admin_ban_menu.send(info.index)
return CommandReturn.BLOCK
# ==============================================================================
# >> EVENTS
# ==============================================================================
@Event('player_disconnect')
def on_player_disconnect(event):
player = Player.from_userid(event['userid'])
ban_system.track_leaver(player.uniqueid, player.name)
@Event('player_death')
def on_player_death(event):
attacker_id = event['attacker']
if event['userid'] == attacker_id:
return
try:
attacker = Player.from_userid(attacker_id)
except ValueError:
return
ban_system.track_freekiller(attacker.uniqueid, attacker.name)
@ClientCommandFilter
def on_client_command(command, index):
if command[0].lower() != 'jointeam':
return
if not (len(command) == 1 or command[1] not in ('1', '2')):
return
uniqueid = uniqueid_from_index(index)
if not ban_system.is_banned(uniqueid):
return
SayText2(
MESSAGE_PREFIX + 'You have been banned from the CT team.').send(index)
return CommandReturn.BLOCK
You need to grant yourself the permission "ctban.open":
http://wiki.sourcepython.com/general/config-auth.html
Re: CTBAN with time and menu
Ayuto, what happens if player chooses autobalance (0)? If it's a jail server (which I assume it is), autobalance would always send you to CT team as there're always much more T players than CT.
Autobalancing also happens not only when you do jointeam 0, but also when you call jointeam with no or with invalid arguments.
Autobalancing also happens not only when you do jointeam 0, but also when you call jointeam with no or with invalid arguments.

My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam
Hail, Companion. [...] Hands to yourself, sneak thief.

Re: CTBAN with time and menu
iPlayer wrote:Ayuto, what happens if player chooses autobalance (0)? If it's a jail server (which I assume it is), autobalance would always send you to CT team as there're always much more T players than CT.
Autobalancing also happens not only when you do jointeam 0, but also when you call jointeam with no or with invalid arguments.
I've never seen a JB server with autobalance, if someone does so, its his/her problem, not the plugin maker.
Re: CTBAN with time and menu
I've never seen a JB server with autobalance, if someone does so, it his/her problem, not the plugin maker.
There's always an autobalance option in team selection screen.
Banned players can possibly exploit it to bypass the ban.

My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam
Hail, Companion. [...] Hands to yourself, sneak thief.

Re: CTBAN with time and menu
Thanks for pointing that out! I will update the plugin tomorrow.
Re: CTBAN with time and menu
Okay, to avoid confusion, I should've probably called it "auto-selection option", not autobalance.
I didn't mean that thing that switches players from time to time automatically, I specifically meant "auto-select" button when you press M or join the server.
I didn't mean that thing that switches players from time to time automatically, I specifically meant "auto-select" button when you press M or join the server.

My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam
Hail, Companion. [...] Hands to yourself, sneak thief.

Re: CTBAN with time and menu
iPlayer wrote:Okay, to avoid confusion, I should've probably called it "auto-selection option", not autobalance.
I didn't mean that thing that switches players from time to time automatically, I specifically meant "auto-select" button when you press M or join the server.
You're right, just tested it, You can join CT by using the auto-selection
Re: CTBAN with time and menu
Okay, I have updated the script above to handle auto-selection as well.
Re: CTBAN with time and menu
Great job! Now the only thing left is invalid arguments :D

Edit: Possible solution:
Edit2: I'd also replace SayText2 with TextMsg (center of the screen) and would do this just before blocking the command:
Also, if somebody did manage to exploit this plugin, maybe register a player_team event listener and move such players back?
Code: Select all
jointeam exploited

Edit: Possible solution:
Syntax: Select all
if len(command) != 1:
return CommandReturn.BLOCK
try:
new_team = int(command[1])
except ValueError:
return CommandReturn.BLOCK
# other checks
Edit2: I'd also replace SayText2 with TextMsg (center of the screen) and would do this just before blocking the command:
Syntax: Select all
VGUIMenu('team', show=True).send(index)
Also, if somebody did manage to exploit this plugin, maybe register a player_team event listener and move such players back?

My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam
Hail, Companion. [...] Hands to yourself, sneak thief.

Re: CTBAN with time and menu
Updated :D
Also updated the add_ban method to remove a banned player from leavers and freekillers. Moreover, track_leaver and track_freekiller will no longer track banned players.
I was also thinking about using a hook to completely disallow that, but I try to avoid hooks if possible.
Also updated the add_ban method to remove a banned player from leavers and freekillers. Moreover, track_leaver and track_freekiller will no longer track banned players.
iPlayer wrote:Also, if somebody did manage to exploit this plugin, maybe register a player_team event listener and move such players back?
I was also thinking about using a hook to completely disallow that, but I try to avoid hooks if possible.
Re: CTBAN with time and menu
Ayuto wrote:Updated :D
Also updated the add_ban method to remove a banned player from leavers and freekillers. Moreover, track_leaver and track_freekiller will no longer track banned players.iPlayer wrote:Also, if somebody did manage to exploit this plugin, maybe register a player_team event listener and move such players back?
I was also thinking about using a hook to completely disallow that, but I try to avoid hooks if possible.
What about this: Play a sound, and show the selection menu again, instead of SayText use TextMsg?
Re: CTBAN with time and menu
Well, that's a matter of preference. If anyone wants that, he is free to use my code and adapt it.
Re: CTBAN with time and menu
I have created a GitHub repo:
https://github.com/Ayuto/CT-Ban
If anyone wants to make changes, he can create a PR or if he wants to develop that further, I can also add him as a collaborator.
https://github.com/Ayuto/CT-Ban
If anyone wants to make changes, he can create a PR or if he wants to develop that further, I can also add him as a collaborator.
Who is online
Users browsing this forum: No registered users and 81 guests