Skip to content

Commit

Permalink
Merge f55303e into adf6177
Browse files Browse the repository at this point in the history
  • Loading branch information
godwhoa committed Aug 17, 2019
2 parents adf6177 + f55303e commit 15264a4
Show file tree
Hide file tree
Showing 19 changed files with 136 additions and 154 deletions.
33 changes: 28 additions & 5 deletions piqueserver/commands.py
Expand Up @@ -268,10 +268,33 @@ def _decorated(connection, *args, **kwargs):
func(connection, *args, **kwargs)
return _decorated

def target_player(func: Callable):
"""This decorator converts first argument of a command to a `piqueserver.FeatureConnection`.
It's intended for commands which accept single argument for target player eg. /fly [player].
It implicitly uses invoker as target if no arguments are provided.
It uses first argument are player name or id for targetting.
It forces non-player invokers to provide player argument.
# TODO: all of these utility functions should be seperated from the actual
# implementation of the commands

>>> @command()
... @target_player
... def fly(connection, target):
... target.fly = True
... pass
"""
@functools.wraps(func)
def _decorated(connection, *args, **kwargs):
is_player = connection in connection.protocol.players.values()
# implicitly set target to invoker if no args
if len(args) == 0 and is_player:
args = [connection]
# try and use first arg as player name or id to target
elif len(args) > 0:
args = [get_player(connection.protocol, args[0]), *args[1:]]
# console or irc invokers are required to provide a target
else:
raise ValueError("Target player is required")
return func(connection, *args, **kwargs)
return _decorated

def get_player(protocol, value: str, spectators=True):
"""
Expand Down Expand Up @@ -427,8 +450,8 @@ def _handle_command(connection, command, parameters):
msg = str(e)
except PermissionDenied as e:
msg = 'You can\'t do that: {}'.format(str(e))
except ValueError:
msg = 'Invalid parameters'
except ValueError as e:
msg = str(e) if e.args else "Invalid parameters"

return format_command_error(command_func, msg)

Expand Down
31 changes: 13 additions & 18 deletions piqueserver/core_commands/game.py
Expand Up @@ -3,7 +3,8 @@
from twisted.internet import reactor
from piqueserver.config import cast_duration
from pyspades.common import prettify_timespan
from piqueserver.commands import command, CommandError, get_player, get_team, get_truthy
from piqueserver.commands import (
command, CommandError, get_player, get_team, get_truthy, target_player)


@command('time')
Expand Down Expand Up @@ -70,26 +71,18 @@ def unlock(connection, value):


@command(admin_only=True)
def switch(connection, player=None, team=None):
@target_player
def switch(connection, player):
"""
Switch teams either for yourself or for a given player
/switch [player]
"""
protocol = connection.protocol
if player is not None:
player = get_player(protocol, player)
elif connection in protocol.players.values():
player = connection
else:
raise ValueError()
if player.team.spectator:
player.send_chat(
"The switch command can't be used on a spectating player.")
return
if team is None:
new_team = player.team.other
else:
new_team = get_team(connection, team)
new_team = player.team.other
if player.invisible:
old_team = player.team
player.team = new_team
Expand Down Expand Up @@ -246,22 +239,24 @@ def fog(connection, *args):
hex_code = args[0][1:]

if (len(hex_code) != 3) and (len(hex_code) != 6):
raise ValueError()
raise ValueError("Invalid hex code length")

if len(hex_code) == 3: # it's a short hex code, turn it into a full one
if len(hex_code) == 3: # it's a short hex code, turn it into a full one
hex_code = (hex_code[0]*2) + (hex_code[1]*2) + (hex_code[2]*2)

valid_characters = re.compile('[a-fA-F0-9]')
for char in hex_code:
if valid_characters.match(char) == None:
raise ValueError()
if valid_characters.match(char) is None:
raise ValueError("Invalid hex code characters")

r = int(hex_code[0:2], base=16)
g = int(hex_code[2:4], base=16)
b = int(hex_code[4:6], base=16)
else:
raise ValueError()
raise ValueError("Neither RGB or hex code provided")

old_fog_color = connection.protocol.fog_color
connection.protocol.set_fog_color((r, g, b))
# TODO: Warn when the fog was set to the same color as before
if old_fog_color == (r, g, b):
return 'Fog color changed successfully\nWarning: fog color set to same color as before'
return 'Fog color changed successfully'
18 changes: 7 additions & 11 deletions piqueserver/core_commands/info.py
@@ -1,4 +1,5 @@
from piqueserver.commands import command, _commands, has_permission, get_player, get_command_help, player_only
from piqueserver.commands import (
command, _commands, has_permission, get_player, get_command_help, player_only, target_player)


@command()
Expand All @@ -13,21 +14,16 @@ def streak(connection):


@command()
def ping(connection, value=None):
@target_player
def ping(connection, player):
"""
Tell your current ping (time for your actions to be received by the server)
/ping
"""
if value is None:
if connection not in connection.protocol.players.values():
raise ValueError()
player = connection
else:
player = get_player(connection.protocol, value)
ping = player.latency
if value is None:
return 'Your ping is %s ms. Lower ping is better!' % ping
return "%s's ping is %s ms" % (player.name, ping)
if connection is player:
return 'Your ping is {} ms. Lower ping is better!'.format(player.latency)
return "{}'s ping is {} ms".format(player.name, player.latency)


@command()
Expand Down
34 changes: 9 additions & 25 deletions piqueserver/core_commands/moderation.py
@@ -1,16 +1,15 @@
from random import choice
from twisted.internet import reactor
# aparently, we need to send packets in this file. For now, I give in.
from pyspades.contained import CreatePlayer, SetTool, KillAction, InputData, SetColor, WeaponInput
from pyspades.constants import (GRENADE_KILL, FALL_KILL, NETWORK_FPS)
from pyspades.common import (
prettify_timespan,
make_color)
from piqueserver.commands import command, CommandError, get_player, join_arguments
from piqueserver.commands import (
command, CommandError, get_player, join_arguments, target_player)
from piqueserver.utils import timeparse

# aparently, we need to send packets in this file. For now, I give in.



def has_digits(s: str) -> bool:
return any(char.isdigit() for char in s)
Expand Down Expand Up @@ -201,17 +200,12 @@ def unmute(connection, value):


@command(admin_only=True)
def ip(connection, value=None):
@target_player
def ip(connection, player):
"""
Get the IP of a user
/ip [player]
"""
if value is None:
if connection not in connection.protocol.players.values():
raise ValueError()
player = connection
else:
player = get_player(connection.protocol, value)
return 'The IP of %s is %s' % (player.name, player.address[0])


Expand All @@ -237,18 +231,13 @@ def who_was(connection, value):


@command('invisible', 'invis', 'inv', admin_only=True)
def invisible(connection, player=None):
@target_player
def invisible(connection, player):
"""
Turn invisible
/invisible [player]
"""
protocol = connection.protocol
if player is not None:
player = get_player(protocol, player)
elif connection in protocol.players.values():
player = connection
else:
raise ValueError()
# TODO: move this logic to a more suitable place
player.invisible = not player.invisible
player.filter_visibility_data = player.invisible
Expand Down Expand Up @@ -364,18 +353,13 @@ def god(connection, player=None):


@command('godbuild', admin_only=True)
def god_build(connection, player=None):
@target_player
def god_build(connection, player):
"""
Place blocks that can be destroyed only by players with godmode activated
/godbuild [player]
"""
protocol = connection.protocol
if player is not None:
player = get_player(protocol, player)
elif connection in protocol.players.values():
player = connection
else:
raise ValueError()

player.god_build = not player.god_build

Expand Down
36 changes: 13 additions & 23 deletions piqueserver/core_commands/movement.py
@@ -1,18 +1,15 @@
from pyspades.common import (coordinates, to_coordinates)
from piqueserver.commands import (command, CommandError, get_player,
PermissionDenied, player_only)
PermissionDenied, player_only, target_player)


@command(admin_only=True)
def unstick(connection, player=None):
@target_player
def unstick(connection, player):
"""
Unstick yourself or another player and inform everyone on the server of it
/unstick [player]
"""
if player is not None:
player = get_player(connection.protocol, player)
else:
player = connection
connection.protocol.send_chat("%s unstuck %s" %
(connection.name, player.name), irc=True)
player.set_location_safe(player.get_location())
Expand Down Expand Up @@ -66,7 +63,8 @@ def do_move(connection, args, silent=False):
elif arg_count == 3 or arg_count == 4:
x = min(max(0, int(args[initial_index])), 511)
y = min(max(0, int(args[initial_index + 1])), 511)
z = min(max(0, int(args[initial_index + 2])), connection.protocol.map.get_height(x, y) - 2)
z = min(max(0, int(args[initial_index + 2])),
connection.protocol.map.get_height(x, y) - 2)
position = '%d %d %d' % (x, y, z)
else:
raise ValueError('Wrong number of parameters!')
Expand All @@ -75,7 +73,7 @@ def do_move(connection, args, silent=False):
if arg_count == 1 or arg_count == 3:
# must be run by a player in this case because moving self
if connection not in connection.protocol.players.values():
raise ValueError()
raise ValueError("Both player and target player are required")
player = connection.name
# player specified
elif arg_count == 2 or arg_count == 4:
Expand Down Expand Up @@ -104,18 +102,15 @@ def do_move(connection, args, silent=False):


@command(admin_only=True)
def where(connection, player=None):
@target_player
def where(connection, player):
"""
Tell you the coordinates of yourself or of a given player
/where [player]
"""
if player is not None:
connection = get_player(connection.protocol, player)
elif connection not in connection.protocol.players.values():
raise ValueError()
x, y, z = connection.get_location()
x, y, z = player.get_location()
return '%s is in %s (%s, %s, %s)' % (
connection.name, to_coordinates(x, y), int(x), int(y), int(z))
player.name, to_coordinates(x, y), int(x), int(y), int(z))


@command('teleport', 'tp', admin_only=True)
Expand All @@ -138,7 +133,7 @@ def teleport(connection, player1, player2=None, silent=False):
return 'No administrator rights!'
else:
if connection not in connection.protocol.players.values():
raise ValueError()
raise ValueError("Both player and target player are required")
player, target = connection, player1
silent = silent or player.invisible
message = '%s ' + \
Expand All @@ -162,19 +157,14 @@ def tpsilent(connection, player1, player2=None):


@command(admin_only=True)
def fly(connection, player=None):
@target_player
def fly(connection, player):
"""
Enable flight
/fly [player]
Hold control and press space ;)
"""
protocol = connection.protocol
if player is not None:
player = get_player(protocol, player)
elif connection in protocol.players.values():
player = connection
else:
raise ValueError()
player.fly = not player.fly

message = 'now flying' if player.fly else 'no longer flying'
Expand Down
22 changes: 9 additions & 13 deletions piqueserver/core_commands/player.py
@@ -1,16 +1,15 @@
from piqueserver.commands import command, get_player, PermissionDenied, player_only
from piqueserver.commands import command, get_player, PermissionDenied, player_only, target_player

@command("client", "cli")
def client(connection, target=None):
@target_player
def client(connection, player):
"""
Tell you information about your client or the client of a given player
/client [player]
"""
if not target:
player = connection
if connection is player:
who_is = "You are"
else:
player = get_player(connection.protocol, target)
who_is = player.name + " is"

return "{} connected with {}".format(who_is, player.client_string)
Expand Down Expand Up @@ -65,19 +64,16 @@ def kill(connection, value=None):


@command(admin_only=True)
def heal(connection, player=None):
@target_player
def heal(connection, player):
"""
Heal and refill yourself or a given player and inform everyone on the server of this action
/heal [player]
"""
if player is not None:
player = get_player(connection.protocol, player, False)
message = '%s was healed by %s' % (player.name, connection.name)
else:
if connection not in connection.protocol.players.values():
raise ValueError()
player = connection
if connection is player:
message = '%s was healed' % (connection.name)
else:
message = '%s was healed by %s' % (player.name, connection.name)
player.refill()
connection.protocol.send_chat(message, irc=True)

Expand Down
2 changes: 1 addition & 1 deletion piqueserver/scripts/afk.py
Expand Up @@ -38,7 +38,7 @@ def kick_afk(connection, minutes, amount=None):
protocol = connection.protocol
minutes = int(minutes)
if minutes < 1:
raise ValueError()
raise ValueError("Minutes cannot be < 1")
to_kick = []
seconds = minutes * 60.0
minutes_s = prettify_timespan(seconds)
Expand Down

0 comments on commit 15264a4

Please sign in to comment.