Even more death and destruction. A lot more stuff moved to src/. A lot more bugs probably introduced.
This commit is contained in:
parent
d3808c1ea2
commit
4bb00013ae
28 changed files with 45 additions and 38 deletions
94
src/ansi.py
Executable file
94
src/ansi.py
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
import re
|
||||
"""
|
||||
ANSI related stuff.
|
||||
"""
|
||||
ansi = {}
|
||||
ansi["beep"] = "\07"
|
||||
ansi["escape"] = "\033"
|
||||
ansi["normal"] = "\033[0m"
|
||||
|
||||
ansi["underline"] = "\033[4m"
|
||||
ansi["hilite"] = "\033[1m"
|
||||
ansi["blink"] = "\033[5m"
|
||||
ansi["inverse"] = "\033[7m"
|
||||
ansi["inv_hilite"] = "\033[1;7m"
|
||||
ansi["inv_blink"] = "\033[7;5m"
|
||||
ansi["blink_hilite"] = "\033[1;5m"
|
||||
ansi["inv_blink_hilite"] = "\033[1;5;7m"
|
||||
|
||||
# Foreground colors
|
||||
ansi["black"] = "\033[30m"
|
||||
ansi["red"] = "\033[31m"
|
||||
ansi["green"] = "\033[32m"
|
||||
ansi["yellow"] = "\033[33m"
|
||||
ansi["blue"] = "\033[34m"
|
||||
ansi["magenta"] = "\033[35m"
|
||||
ansi["cyan"] = "\033[36m"
|
||||
ansi["white"] = "\033[37m"
|
||||
|
||||
# Background colors
|
||||
ansi["back_black"] = "\033[40m"
|
||||
ansi["back_red"] = "\033[41m"
|
||||
ansi["back_green"] = "\033[42m"
|
||||
ansi["back_yellow"] = "\033[43m"
|
||||
ansi["back_blue"] = "\033[44m"
|
||||
ansi["back_magenta"] = "\033[45m"
|
||||
ansi["back_cyan"] = "\033[46m"
|
||||
ansi["back_white"] = "\033[47m"
|
||||
|
||||
# Formatting Characters
|
||||
ansi["return"] = "\r\n"
|
||||
ansi["tab"] = "\t"
|
||||
ansi["space"] = " "
|
||||
|
||||
def parse_ansi(string, strip_ansi=False, strip_formatting=False):
|
||||
"""
|
||||
Parses a string, subbing color codes as needed.
|
||||
"""
|
||||
if strip_formatting:
|
||||
char_return = ""
|
||||
char_tab = ""
|
||||
char_space = ""
|
||||
else:
|
||||
char_return = ansi["return"]
|
||||
char_tab = ansi["tab"]
|
||||
char_space = ansi["space"]
|
||||
|
||||
ansi_subs = [
|
||||
(r'%r', char_return),
|
||||
(r'%t', char_tab),
|
||||
(r'%b', char_space),
|
||||
(r'%cf', ansi["blink"]),
|
||||
(r'%ci', ansi["inverse"]),
|
||||
(r'%ch', ansi["hilite"]),
|
||||
(r'%cn', ansi["normal"]),
|
||||
(r'%cx', ansi["black"]),
|
||||
(r'%cX', ansi["back_black"]),
|
||||
(r'%cr', ansi["red"]),
|
||||
(r'%cR', ansi["back_red"]),
|
||||
(r'%cg', ansi["green"]),
|
||||
(r'%cG', ansi["back_green"]),
|
||||
(r'%cy', ansi["yellow"]),
|
||||
(r'%cY', ansi["back_yellow"]),
|
||||
(r'%cb', ansi["blue"]),
|
||||
(r'%cB', ansi["back_blue"]),
|
||||
(r'%cm', ansi["magenta"]),
|
||||
(r'%cM', ansi["back_magenta"]),
|
||||
(r'%cc', ansi["cyan"]),
|
||||
(r'%cC', ansi["back_cyan"]),
|
||||
(r'%cw', ansi["white"]),
|
||||
(r'%cW', ansi["back_white"]),
|
||||
]
|
||||
|
||||
for sub in ansi_subs:
|
||||
p = re.compile(sub[0], re.DOTALL)
|
||||
if strip_ansi:
|
||||
string = p.sub("", string)
|
||||
else:
|
||||
string = p.sub(sub[1], string)
|
||||
|
||||
if strip_ansi:
|
||||
return '%s' % (string)
|
||||
else:
|
||||
return '%s%s' % (string, ansi["normal"])
|
||||
|
||||
258
src/cmdhandler.py
Executable file
258
src/cmdhandler.py
Executable file
|
|
@ -0,0 +1,258 @@
|
|||
"""
|
||||
This is the command processing module. It is instanced once in the main
|
||||
server module and the handle() function is hit every time a player sends
|
||||
something.
|
||||
"""
|
||||
from traceback import format_exc
|
||||
import time
|
||||
|
||||
from apps.objects.models import Object
|
||||
import defines_global
|
||||
import cmdtable
|
||||
import functions_general
|
||||
import functions_log
|
||||
import functions_comsys
|
||||
|
||||
class UnknownCommand(Exception):
|
||||
"""
|
||||
Throw this when a user enters an an invalid command.
|
||||
"""
|
||||
|
||||
def match_exits(pobject, searchstr):
|
||||
"""
|
||||
See if we can find an input match to exits.
|
||||
"""
|
||||
exits = pobject.get_location().get_contents(filter_type=4)
|
||||
return Object.objects.list_search_object_namestr(exits, searchstr, match_type="exact")
|
||||
|
||||
def parse_command(command_string):
|
||||
"""
|
||||
Tries to handle the most common command strings and returns a dictionary with various data.
|
||||
Common command types:
|
||||
- Complex:
|
||||
@pemit[/option] <target>[/option]=<data>
|
||||
- Simple:
|
||||
look
|
||||
look <target>
|
||||
|
||||
I'm not married to either of these terms, but I couldn't think of anything better. If you can, lets change it :)
|
||||
|
||||
The only cases that I haven't handled is if someone enters something like:
|
||||
@pemit <target> <target>/<switch>=<data>
|
||||
- Ends up considering both targets as one with a space between them, and the switch as a switch.
|
||||
@pemit <target>/<switch> <target>=<data>
|
||||
- Ends up considering the first target a target, and the second target as part of the switch.
|
||||
|
||||
|
||||
"""
|
||||
# Each of the bits of data starts off as None, except for the raw, original
|
||||
# command
|
||||
parsed_command = dict(
|
||||
raw_command=command_string,
|
||||
data=None,
|
||||
original_command=None,
|
||||
original_targets=None,
|
||||
base_command=None,
|
||||
command_switches=None,
|
||||
targets=None,
|
||||
target_switches=None
|
||||
)
|
||||
try:
|
||||
# If we make it past this next statement, then this is what we
|
||||
# consider a complex command
|
||||
(command_parts, data) = command_string.split('=', 1)
|
||||
parsed_command['data'] = data
|
||||
# First we deal with the command part of the command and break it
|
||||
# down into the base command, along with switches
|
||||
# If we make it past the next statement, then they must have
|
||||
# entered a command like:
|
||||
# p =<data>
|
||||
# So we should probably just let it get caught by the ValueError
|
||||
# again and consider it a simple command
|
||||
(total_command, total_targets) = command_parts.split(' ', 1)
|
||||
parsed_command['original_command'] = total_command
|
||||
parsed_command['original_targets'] = total_targets
|
||||
split_command = total_command.split('/')
|
||||
parsed_command['base_command'] = split_command[0]
|
||||
parsed_command['command_switches'] = split_command[1:]
|
||||
# Now we move onto the target data
|
||||
try:
|
||||
# Look for switches- if they give target switches, then we don't
|
||||
# accept multiple targets
|
||||
(target, switch_string) = total_targets.split('/', 1)
|
||||
parsed_command['targets'] = [target]
|
||||
parsed_command['target_switches'] = switch_string.split('/')
|
||||
except ValueError:
|
||||
# Alright, no switches, so lets consider multiple targets
|
||||
parsed_command['targets'] = total_targets.split()
|
||||
except ValueError:
|
||||
# Ok, couldn't find an =, so not a complex command
|
||||
try:
|
||||
(command, data) = command_string.split(' ', 1)
|
||||
parsed_command['base_command'] = command
|
||||
parsed_command['data'] = data
|
||||
except ValueError:
|
||||
# No arguments
|
||||
# ie:
|
||||
# - look
|
||||
parsed_command['base_command'] = command_string
|
||||
return parsed_command
|
||||
|
||||
def handle(cdat):
|
||||
"""
|
||||
Use the spliced (list) uinput variable to retrieve the correct
|
||||
command, or return an invalid command error.
|
||||
|
||||
We're basically grabbing the player's command by tacking
|
||||
their input on to 'cmd_' and looking it up in the GenCommands
|
||||
class.
|
||||
"""
|
||||
session = cdat['session']
|
||||
server = cdat['server']
|
||||
|
||||
try:
|
||||
# TODO: Protect against non-standard characters.
|
||||
if cdat['uinput'] == '':
|
||||
return
|
||||
|
||||
parsed_input = {}
|
||||
parsed_input['parsed_command'] = parse_command(cdat['uinput'])
|
||||
|
||||
# First we split the input up by spaces.
|
||||
parsed_input['splitted'] = cdat['uinput'].split()
|
||||
# Now we find the root command chunk (with switches attached).
|
||||
parsed_input['root_chunk'] = parsed_input['splitted'][0].split('/')
|
||||
# And now for the actual root command. It's the first entry in root_chunk.
|
||||
parsed_input['root_cmd'] = parsed_input['root_chunk'][0].lower()
|
||||
# Keep around the full, raw input in case a command needs it
|
||||
cdat['raw_input'] = cdat['uinput']
|
||||
|
||||
# Now we'll see if the user is using an alias. We do a dictionary lookup,
|
||||
# if the key (the player's root command) doesn't exist on the dict, we
|
||||
# don't replace the existing root_cmd. If the key exists, its value
|
||||
# replaces the previously splitted root_cmd. For example, sa -> say.
|
||||
alias_list = server.cmd_alias_list
|
||||
parsed_input['root_cmd'] = alias_list.get(parsed_input['root_cmd'],parsed_input['root_cmd'])
|
||||
|
||||
# This will hold the reference to the command's function.
|
||||
cmd = None
|
||||
|
||||
if session.logged_in:
|
||||
# Store the timestamp of the user's last command.
|
||||
session.cmd_last = time.time()
|
||||
|
||||
# Lets the users get around badly configured NAT timeouts.
|
||||
if parsed_input['root_cmd'] == 'idle':
|
||||
return
|
||||
|
||||
# Increment our user's command counter.
|
||||
session.cmd_total += 1
|
||||
# Player-visible idle time, not used in idle timeout calcs.
|
||||
session.cmd_last_visible = time.time()
|
||||
|
||||
# Just in case. Prevents some really funky-case crashes.
|
||||
if len(parsed_input['root_cmd']) == 0:
|
||||
raise UnknownCommand
|
||||
|
||||
# Shortened say alias.
|
||||
if parsed_input['root_cmd'][0] == '"':
|
||||
parsed_input['splitted'].insert(0, "say")
|
||||
parsed_input['splitted'][1] = parsed_input['splitted'][1][1:]
|
||||
parsed_input['root_cmd'] = 'say'
|
||||
# Shortened pose alias.
|
||||
elif parsed_input['root_cmd'][0] == ':':
|
||||
parsed_input['splitted'].insert(0, "pose")
|
||||
parsed_input['splitted'][1] = parsed_input['splitted'][1][1:]
|
||||
parsed_input['root_cmd'] = 'pose'
|
||||
# Pose without space alias.
|
||||
elif parsed_input['root_cmd'][0] == ';':
|
||||
parsed_input['splitted'].insert(0, "pose/nospace")
|
||||
parsed_input['root_chunk'] = ['pose', 'nospace']
|
||||
parsed_input['splitted'][1] = parsed_input['splitted'][1][1:]
|
||||
parsed_input['root_cmd'] = 'pose'
|
||||
# Channel alias match.
|
||||
elif functions_comsys.plr_has_channel(session,
|
||||
parsed_input['root_cmd'],
|
||||
alias_search=True,
|
||||
return_muted=True):
|
||||
|
||||
calias = parsed_input['root_cmd']
|
||||
cname = functions_comsys.plr_cname_from_alias(session, calias)
|
||||
cmessage = ' '.join(parsed_input['splitted'][1:])
|
||||
|
||||
if cmessage == "who":
|
||||
functions_comsys.msg_cwho(session, cname)
|
||||
return
|
||||
elif cmessage == "on":
|
||||
functions_comsys.plr_chan_on(session, calias)
|
||||
return
|
||||
elif cmessage == "off":
|
||||
functions_comsys.plr_chan_off(session, calias)
|
||||
return
|
||||
elif cmessage == "last":
|
||||
functions_comsys.msg_chan_hist(session, cname)
|
||||
return
|
||||
|
||||
second_arg = "%s=%s" % (cname, cmessage)
|
||||
parsed_input['splitted'] = ["@cemit/sendername", second_arg]
|
||||
parsed_input['root_chunk'] = ['@cemit', 'sendername', 'quiet']
|
||||
parsed_input['root_cmd'] = '@cemit'
|
||||
|
||||
# Get the command's function reference (Or False)
|
||||
cmdtuple = cmdtable.return_cmdtuple(parsed_input['root_cmd'])
|
||||
if cmdtuple:
|
||||
# If there is a permissions element to the entry, check perms.
|
||||
if cmdtuple[1]:
|
||||
if not session.get_pobject().user_has_perm_list(cmdtuple[1]):
|
||||
session.msg(defines_global.NOPERMS_MSG)
|
||||
return
|
||||
# If flow reaches this point, user has perms and command is ready.
|
||||
cmd = cmdtuple[0]
|
||||
|
||||
else:
|
||||
# Not logged in, look through the unlogged-in command table.
|
||||
cmdtuple = cmdtable.return_cmdtuple(parsed_input['root_cmd'], unlogged_cmd=True)
|
||||
if cmdtuple:
|
||||
cmd = cmdtuple[0]
|
||||
|
||||
# Debugging stuff.
|
||||
#session.msg("ROOT : %s" % (parsed_input['root_cmd'],))
|
||||
#session.msg("SPLIT: %s" % (parsed_input['splitted'],))
|
||||
|
||||
if callable(cmd):
|
||||
cdat['uinput'] = parsed_input
|
||||
try:
|
||||
cmd(cdat)
|
||||
except:
|
||||
session.msg("Untrapped error, please file a bug report:\n%s" % (format_exc(),))
|
||||
functions_log.log_errmsg("Untrapped error, evoker %s: %s" %
|
||||
(session, format_exc()))
|
||||
return
|
||||
|
||||
if session.logged_in:
|
||||
# If we're not logged in, don't check exits.
|
||||
pobject = session.get_pobject()
|
||||
exit_matches = match_exits(pobject, ' '.join(parsed_input['splitted']))
|
||||
if exit_matches:
|
||||
targ_exit = exit_matches[0]
|
||||
if targ_exit.get_home():
|
||||
cdat['uinput'] = parsed_input
|
||||
|
||||
# SCRIPT: See if the player can traverse the exit
|
||||
if not targ_exit.get_scriptlink().default_lock({
|
||||
"pobject": pobject
|
||||
}):
|
||||
session.msg("You can't traverse that exit.")
|
||||
else:
|
||||
pobject.move_to(targ_exit.get_home())
|
||||
session.execute_cmd("look")
|
||||
else:
|
||||
session.msg("That exit leads to nowhere.")
|
||||
return
|
||||
|
||||
# If we reach this point, we haven't matched anything.
|
||||
raise UnknownCommand
|
||||
|
||||
except UnknownCommand:
|
||||
session.msg("Huh? (Type \"help\" for help.)")
|
||||
|
||||
89
src/cmdtable.py
Normal file
89
src/cmdtable.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"""
|
||||
Command Table Entries
|
||||
---------------------
|
||||
Each command entry consists of a key and a tuple containing a reference to the
|
||||
command's function, and a tuple of the permissions to match against. The user
|
||||
only need have one of the permissions in the permissions tuple to gain
|
||||
access to the command. Obviously, super users don't have to worry about this
|
||||
stuff. If the command is open to all (or you want to implement your own
|
||||
privilege checking in the command function), use None in place of the
|
||||
permissions tuple.
|
||||
"""
|
||||
import commands.general
|
||||
import commands.privileged
|
||||
import commands.comsys
|
||||
import commands.unloggedin
|
||||
import commands.info
|
||||
import commands.objmanip
|
||||
|
||||
# -- Unlogged-in Command Table --
|
||||
# Command Name Command Function Privilege Tuple
|
||||
uncon_ctable = {
|
||||
"connect": (commands.unloggedin.cmd_connect, None),
|
||||
"create": (commands.unloggedin.cmd_create, None),
|
||||
"quit": (commands.unloggedin.cmd_quit, None),
|
||||
}
|
||||
|
||||
|
||||
# -- Command Table --
|
||||
# Command Name Command Function Privilege Tuple
|
||||
ctable = {
|
||||
"addcom": (commands.comsys.cmd_addcom, None),
|
||||
"comlist": (commands.comsys.cmd_comlist, None),
|
||||
"delcom": (commands.comsys.cmd_delcom, None),
|
||||
"drop": (commands.general.cmd_drop, None),
|
||||
"examine": (commands.general.cmd_examine, None),
|
||||
"get": (commands.general.cmd_get, None),
|
||||
"help": (commands.general.cmd_help, None),
|
||||
"idle": (commands.general.cmd_idle, None),
|
||||
"inventory": (commands.general.cmd_inventory, None),
|
||||
"look": (commands.general.cmd_look, None),
|
||||
"page": (commands.general.cmd_page, None),
|
||||
"pose": (commands.general.cmd_pose, None),
|
||||
"quit": (commands.general.cmd_quit, None),
|
||||
"say": (commands.general.cmd_say, None),
|
||||
"time": (commands.info.cmd_time, None),
|
||||
"uptime": (commands.info.cmd_uptime, None),
|
||||
"version": (commands.info.cmd_version, None),
|
||||
"who": (commands.general.cmd_who, None),
|
||||
"@alias": (commands.objmanip.cmd_alias, None),
|
||||
"@boot": (commands.privileged.cmd_boot, ("genperms.manage_players")),
|
||||
"@ccreate": (commands.comsys.cmd_ccreate, ("objects.add_commchannel")),
|
||||
"@cdestroy": (commands.comsys.cmd_cdestroy, ("objects.delete_commchannel")),
|
||||
"@cemit": (commands.comsys.cmd_cemit, None),
|
||||
"@clist": (commands.comsys.cmd_clist, None),
|
||||
"@create": (commands.objmanip.cmd_create, ("genperms.builder")),
|
||||
"@describe": (commands.objmanip.cmd_description, None),
|
||||
"@destroy": (commands.objmanip.cmd_destroy, ("genperms.builder")),
|
||||
"@dig": (commands.objmanip.cmd_dig, ("genperms.builder")),
|
||||
"@emit": (commands.general.cmd_emit, ("genperms.announce")),
|
||||
# "@pemit": (commands.general.cmd_pemit, None),
|
||||
"@find": (commands.objmanip.cmd_find, ("genperms.builder")),
|
||||
"@link": (commands.objmanip.cmd_link, ("genperms.builder")),
|
||||
"@list": (commands.info.cmd_list, ("genperms.process_control")),
|
||||
"@name": (commands.objmanip.cmd_name, None),
|
||||
"@nextfree": (commands.objmanip.cmd_nextfree, ("genperms.builder")),
|
||||
"@newpassword": (commands.privileged.cmd_newpassword, ("genperms.manage_players")),
|
||||
"@open": (commands.objmanip.cmd_open, ("genperms.builder")),
|
||||
"@password": (commands.general.cmd_password, None),
|
||||
"@ps": (commands.info.cmd_ps, ("genperms.process_control")),
|
||||
"@reload": (commands.privileged.cmd_reload, ("genperms.process_control")),
|
||||
"@set": (commands.objmanip.cmd_set, None),
|
||||
"@shutdown": (commands.privileged.cmd_shutdown, ("genperms.process_control")),
|
||||
"@stats": (commands.info.cmd_stats, None),
|
||||
"@teleport": (commands.objmanip.cmd_teleport, ("genperms.builder")),
|
||||
"@unlink": (commands.objmanip.cmd_unlink, ("genperms.builder")),
|
||||
"@wall": (commands.general.cmd_wall, ("genperms.announce")),
|
||||
"@wipe": (commands.objmanip.cmd_wipe, None),
|
||||
}
|
||||
|
||||
def return_cmdtuple(func_name, unlogged_cmd=False):
|
||||
"""
|
||||
Returns a reference to the command's tuple. If there are no matches,
|
||||
returns false.
|
||||
"""
|
||||
if not unlogged_cmd:
|
||||
cfunc = ctable.get(func_name, False)
|
||||
else:
|
||||
cfunc = uncon_ctable.get(func_name, False)
|
||||
return cfunc
|
||||
0
src/commands/__init__.py
Normal file
0
src/commands/__init__.py
Normal file
292
src/commands/comsys.py
Normal file
292
src/commands/comsys.py
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
"""
|
||||
Comsys command module. Pretty much every comsys command should go here for
|
||||
now.
|
||||
"""
|
||||
import time
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import functions_general
|
||||
import functions_comsys
|
||||
import defines_global
|
||||
from src import ansi
|
||||
|
||||
def cmd_addcom(cdat):
|
||||
"""
|
||||
addcom
|
||||
|
||||
Adds an alias for a channel.
|
||||
addcom foo=Bar
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("You need to specify a channel alias and name.")
|
||||
return
|
||||
|
||||
eq_args = args[0].split('=')
|
||||
|
||||
if len(eq_args) < 2:
|
||||
session.msg("You need to specify a channel name.")
|
||||
return
|
||||
|
||||
chan_alias = eq_args[0]
|
||||
chan_name = eq_args[1]
|
||||
|
||||
if len(chan_name) == 0:
|
||||
session.msg("You need to specify a channel name.")
|
||||
return
|
||||
|
||||
if chan_alias in session.channels_subscribed:
|
||||
session.msg("You are already on that channel.")
|
||||
return
|
||||
|
||||
name_matches = functions_comsys.cname_search(chan_name, exact=True)
|
||||
|
||||
if name_matches:
|
||||
chan_name_parsed = name_matches[0].get_name()
|
||||
session.msg("You join %s, with an alias of %s." % \
|
||||
(chan_name_parsed, chan_alias))
|
||||
functions_comsys.plr_set_channel(session, chan_alias, chan_name_parsed, True)
|
||||
|
||||
# Announce the user's joining.
|
||||
join_msg = "[%s] %s has joined the channel." % \
|
||||
(chan_name_parsed, pobject.get_name(show_dbref=False))
|
||||
functions_comsys.send_cmessage(chan_name_parsed, join_msg)
|
||||
else:
|
||||
session.msg("Could not find channel %s." % (chan_name,))
|
||||
|
||||
def cmd_delcom(cdat):
|
||||
"""
|
||||
delcom
|
||||
|
||||
Removes the specified alias to a channel. If this is the last alias,
|
||||
the user is effectively removed from the channel.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
uinput= cdat['uinput']['splitted']
|
||||
chan_alias = ' '.join(uinput[1:])
|
||||
|
||||
if len(chan_alias) == 0:
|
||||
session.msg("You must specify a channel alias.")
|
||||
return
|
||||
|
||||
if chan_alias not in session.channels_subscribed:
|
||||
session.msg("You are not on that channel.")
|
||||
return
|
||||
|
||||
chan_name = session.channels_subscribed[chan_alias][0]
|
||||
session.msg("You have left %s." % (chan_name,))
|
||||
functions_comsys.plr_del_channel(session, chan_alias)
|
||||
|
||||
# Announce the user's leaving.
|
||||
leave_msg = "[%s] %s has left the channel." % \
|
||||
(chan_name, pobject.get_name(show_dbref=False))
|
||||
functions_comsys.send_cmessage(chan_name, leave_msg)
|
||||
|
||||
def cmd_comlist(cdat):
|
||||
"""
|
||||
Lists the channels a user is subscribed to.
|
||||
"""
|
||||
session = cdat['session']
|
||||
|
||||
session.msg("Alias Channel Status")
|
||||
for chan in session.channels_subscribed:
|
||||
if session.channels_subscribed[chan][1]:
|
||||
chan_on = "On"
|
||||
else:
|
||||
chan_on = "Off"
|
||||
|
||||
session.msg("%-9.9s %-19.19s %s" %
|
||||
(chan, session.channels_subscribed[chan][0], chan_on))
|
||||
session.msg("-- End of comlist --")
|
||||
|
||||
def cmd_allcom(cdat):
|
||||
"""
|
||||
allcom
|
||||
|
||||
Allows the user to universally turn off or on all channels they are on,
|
||||
as well as perform a "who" for all channels they are on.
|
||||
"""
|
||||
pass
|
||||
|
||||
def cmd_clearcom(cdat):
|
||||
"""
|
||||
clearcom
|
||||
|
||||
Effectively runs delcom on all channels the user is on. It will remove their aliases,
|
||||
remove them from the channel, and clear any titles they have set.
|
||||
"""
|
||||
pass
|
||||
|
||||
def cmd_clist(cdat):
|
||||
"""
|
||||
@clist
|
||||
|
||||
Lists all available channels on the game.
|
||||
"""
|
||||
session = cdat['session']
|
||||
session.msg("** Channel Owner Description")
|
||||
for chan in functions_comsys.get_all_channels():
|
||||
session.msg("%s%s %-13.13s %-15.15s %-45.45s" %
|
||||
('-', '-', chan.get_name(), chan.get_owner().get_name(), 'No Description'))
|
||||
session.msg("-- End of Channel List --")
|
||||
|
||||
def cmd_cdestroy(cdat):
|
||||
"""
|
||||
@cdestroy
|
||||
|
||||
Destroys a channel.
|
||||
"""
|
||||
session = cdat['session']
|
||||
uinput= cdat['uinput']['splitted']
|
||||
cname = ' '.join(uinput[1:])
|
||||
|
||||
if cname == '':
|
||||
session.msg("You must supply a name!")
|
||||
return
|
||||
|
||||
name_matches = functions_comsys.cname_search(cname, exact=True)
|
||||
|
||||
if not name_matches:
|
||||
session.msg("Could not find channel %s." % (cname,))
|
||||
else:
|
||||
session.msg("Channel %s destroyed." % (name_matches[0],))
|
||||
name_matches.delete()
|
||||
|
||||
def cmd_cset(cdat):
|
||||
"""
|
||||
@cset
|
||||
|
||||
Sets various flags on a channel.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def cmd_ccharge(cdat):
|
||||
"""
|
||||
@ccharge
|
||||
|
||||
Sets the cost to transmit over a channel. Default is free.
|
||||
"""
|
||||
pass
|
||||
|
||||
def cmd_cboot(cdat):
|
||||
"""
|
||||
@cboot
|
||||
|
||||
Kicks a player or object from the channel.
|
||||
"""
|
||||
pass
|
||||
|
||||
def cmd_cemit(cdat):
|
||||
"""
|
||||
@cemit
|
||||
@cemit/noheader <message>
|
||||
@cemit/sendername <message>
|
||||
|
||||
Allows the user to send a message over a channel as long as
|
||||
they own or control it. It does not show the user's name unless they
|
||||
provide the /sendername switch.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
switches = cdat['uinput']['root_chunk'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Channel emit what?")
|
||||
return
|
||||
|
||||
# Combine the arguments into one string, split it by equal signs into
|
||||
# channel (entry 0 in the list), and message (entry 1 and above).
|
||||
eq_args = ' '.join(args).split('=')
|
||||
cname = eq_args[0]
|
||||
cmessage = ' '.join(eq_args[1:])
|
||||
if len(eq_args) != 2:
|
||||
session.msg("You must provide a channel name and a message to emit.")
|
||||
return
|
||||
if len(cname) == 0:
|
||||
session.msg("You must provide a channel name to emit to.")
|
||||
return
|
||||
if len(cmessage) == 0:
|
||||
session.msg("You must provide a message to emit.")
|
||||
return
|
||||
|
||||
name_matches = functions_comsys.cname_search(cname, exact=True)
|
||||
|
||||
try:
|
||||
# Safety first, kids!
|
||||
cname_parsed = name_matches[0].get_name()
|
||||
except:
|
||||
session.msg("Could not find channel %s." % (cname,))
|
||||
return
|
||||
|
||||
if "noheader" in switches:
|
||||
if not pobject.user_has_perm("objects.emit_commchannel"):
|
||||
session.msg(defines_global.NOPERMS_MSG)
|
||||
return
|
||||
final_cmessage = cmessage
|
||||
else:
|
||||
if "sendername" in switches:
|
||||
if not functions_comsys.plr_has_channel(session, cname_parsed, return_muted=False):
|
||||
session.msg("You must be on %s to do that." % (cname_parsed,))
|
||||
return
|
||||
final_cmessage = "[%s] %s: %s" % (cname_parsed, pobject.get_name(show_dbref=False), cmessage)
|
||||
else:
|
||||
if not pobject.user_has_perm("objects.emit_commchannel"):
|
||||
session.msg(defines_global.NOPERMS_MSG)
|
||||
return
|
||||
final_cmessage = "[%s] %s" % (cname_parsed, cmessage)
|
||||
|
||||
if not "quiet" in switches:
|
||||
session.msg("Sent - %s" % (name_matches[0],))
|
||||
functions_comsys.send_cmessage(cname_parsed, final_cmessage)
|
||||
|
||||
def cmd_cwho(cdat):
|
||||
"""
|
||||
@cwho
|
||||
|
||||
Displays the name, status and object type for a given channel.
|
||||
Adding /all after the channel name will list disconnected players
|
||||
as well.
|
||||
"""
|
||||
pass
|
||||
|
||||
def cmd_ccreate(cdat):
|
||||
"""
|
||||
@ccreate
|
||||
|
||||
Creates a new channel with the invoker being the default owner.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
uinput= cdat['uinput']['splitted']
|
||||
cname = ' '.join(uinput[1:])
|
||||
|
||||
if cname == '':
|
||||
session.msg("You must supply a name!")
|
||||
return
|
||||
|
||||
name_matches = functions_comsys.cname_search(cname, exact=True)
|
||||
|
||||
if name_matches:
|
||||
session.msg("A channel with that name already exists.")
|
||||
else:
|
||||
# Create and set the object up.
|
||||
cdat = {"name": cname, "owner": pobject}
|
||||
new_chan = functions_comsys.create_channel(cdat)
|
||||
session.msg("Channel %s created." % (new_chan.get_name(),))
|
||||
|
||||
def cmd_cchown(cdat):
|
||||
"""
|
||||
@cchown
|
||||
|
||||
Changes the owner of a channel.
|
||||
"""
|
||||
pass
|
||||
537
src/commands/general.py
Normal file
537
src/commands/general.py
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
"""
|
||||
Generic command module. Pretty much every command should go here for
|
||||
now.
|
||||
"""
|
||||
import time
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from apps.config.models import ConfigValue
|
||||
from apps.helpsys.models import HelpEntry
|
||||
from apps.objects.models import Object
|
||||
import functions_general
|
||||
import defines_global
|
||||
from src import session_mgr
|
||||
from src import ansi
|
||||
|
||||
def cmd_password(cdat):
|
||||
"""
|
||||
Changes your own password.
|
||||
|
||||
@newpass <Oldpass>=<Newpass>
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
eq_args = ' '.join(args).split('=')
|
||||
oldpass = ''.join(eq_args[0])
|
||||
newpass = ''.join(eq_args[1:])
|
||||
|
||||
if len(oldpass) == 0:
|
||||
session.msg("You must provide your old password.")
|
||||
elif len(newpass) == 0:
|
||||
session.msg("You must provide your new password.")
|
||||
else:
|
||||
uaccount = pobject.get_user_account()
|
||||
|
||||
if not uaccount.check_password(oldpass):
|
||||
session.msg("The specified old password isn't correct.")
|
||||
elif len(newpass) < 3:
|
||||
session.msg("Passwords must be at least three characters long.")
|
||||
return
|
||||
else:
|
||||
uaccount.set_password(newpass)
|
||||
uaccount.save()
|
||||
session.msg("Password changed.")
|
||||
|
||||
def cmd_emit(cdat):
|
||||
"""
|
||||
Emits something to your location.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
uinput= cdat['uinput']['splitted']
|
||||
message = ' '.join(uinput[1:])
|
||||
|
||||
if message == '':
|
||||
session.msg("Emit what?")
|
||||
else:
|
||||
pobject.get_location().emit_to_contents(message)
|
||||
|
||||
def cmd_wall(cdat):
|
||||
"""
|
||||
Announces a message to all connected players.
|
||||
"""
|
||||
session = cdat['session']
|
||||
wallstring = ' '.join(cdat['uinput']['splitted'][1:])
|
||||
pobject = session.get_pobject()
|
||||
|
||||
if wallstring == '':
|
||||
session.msg("Announce what?")
|
||||
return
|
||||
|
||||
message = "%s shouts \"%s\"" % (session.get_pobject().get_name(show_dbref=False), wallstring)
|
||||
functions_general.announce_all(message)
|
||||
|
||||
def cmd_idle(cdat):
|
||||
"""
|
||||
Returns nothing, this lets the player set an idle timer without spamming
|
||||
his screen.
|
||||
"""
|
||||
pass
|
||||
|
||||
def cmd_inventory(cdat):
|
||||
"""
|
||||
Shows a player's inventory.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
session.msg("You are carrying:")
|
||||
|
||||
for item in pobject.get_contents():
|
||||
session.msg(" %s" % (item.get_name(),))
|
||||
|
||||
money = int(pobject.get_attribute_value("MONEY", default=0))
|
||||
if money == 1:
|
||||
money_name = ConfigValue.objects.get_configvalue("MONEY_NAME_SINGULAR")
|
||||
else:
|
||||
money_name = ConfigValue.objects.get_configvalue("MONEY_NAME_PLURAL")
|
||||
|
||||
session.msg("You have %d %s." % (money,money_name))
|
||||
|
||||
def cmd_look(cdat):
|
||||
"""
|
||||
Handle looking at objects.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
target_obj = pobject.get_location()
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args))
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
# SCRIPT: Get the item's appearance from the scriptlink.
|
||||
session.msg(target_obj.get_scriptlink().return_appearance({
|
||||
"target_obj": target_obj,
|
||||
"pobject": pobject
|
||||
}))
|
||||
|
||||
# SCRIPT: Call the object's script's a_desc() method.
|
||||
target_obj.get_scriptlink().a_desc({
|
||||
"target_obj": pobject
|
||||
})
|
||||
|
||||
def cmd_get(cdat):
|
||||
"""
|
||||
Get an object and put it in a player's inventory.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
plr_is_staff = pobject.is_staff()
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Get what?")
|
||||
return
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args), search_contents=False)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if pobject == target_obj:
|
||||
session.msg("You can't get yourself.")
|
||||
return
|
||||
|
||||
if not plr_is_staff and (target_obj.is_player() or target_obj.is_exit()):
|
||||
session.msg("You can't get that.")
|
||||
return
|
||||
|
||||
if target_obj.is_room() or target_obj.is_garbage() or target_obj.is_going():
|
||||
session.msg("You can't get that.")
|
||||
return
|
||||
|
||||
target_obj.move_to(pobject, quiet=True)
|
||||
session.msg("You pick up %s." % (target_obj.get_name(),))
|
||||
pobject.get_location().emit_to_contents("%s picks up %s." % (pobject.get_name(), target_obj.get_name()), exclude=pobject)
|
||||
|
||||
# SCRIPT: Call the object's script's a_get() method.
|
||||
target_obj.get_scriptlink().a_get({
|
||||
"pobject": pobject
|
||||
})
|
||||
|
||||
def cmd_drop(cdat):
|
||||
"""
|
||||
Drop an object from a player's inventory into their current location.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
plr_is_staff = pobject.is_staff()
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Drop what?")
|
||||
return
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args), search_location=False)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if not pobject == target_obj.get_location():
|
||||
session.msg("You don't appear to be carrying that.")
|
||||
return
|
||||
|
||||
target_obj.move_to(pobject.get_location(), quiet=True)
|
||||
session.msg("You drop %s." % (target_obj.get_name(),))
|
||||
pobject.get_location().emit_to_contents("%s drops %s." % (pobject.get_name(), target_obj.get_name()), exclude=pobject)
|
||||
|
||||
# SCRIPT: Call the object's script's a_drop() method.
|
||||
target_obj.get_scriptlink().a_drop({
|
||||
"pobject": pobject
|
||||
})
|
||||
|
||||
def cmd_examine(cdat):
|
||||
"""
|
||||
Detailed object examine command
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
attr_search = False
|
||||
|
||||
if len(args) == 0:
|
||||
# If no arguments are provided, examine the invoker's location.
|
||||
target_obj = pobject.get_location()
|
||||
else:
|
||||
# Look for a slash in the input, indicating an attribute search.
|
||||
attr_split = args[0].split("/")
|
||||
|
||||
# If the splitting by the "/" character returns a list with more than 1
|
||||
# entry, it's an attribute match.
|
||||
if len(attr_split) > 1:
|
||||
attr_search = True
|
||||
# Strip the object search string from the input with the
|
||||
# object/attribute pair.
|
||||
searchstr = attr_split[0]
|
||||
# Just in case there's a slash in an attribute name.
|
||||
attr_searchstr = '/'.join(attr_split[1:])
|
||||
else:
|
||||
searchstr = ' '.join(args)
|
||||
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, searchstr)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if attr_search:
|
||||
attr_matches = target_obj.attribute_namesearch(attr_searchstr)
|
||||
if attr_matches:
|
||||
for attribute in attr_matches:
|
||||
session.msg(attribute.get_attrline())
|
||||
else:
|
||||
session.msg("No matching attributes found.")
|
||||
# End attr_search if()
|
||||
else:
|
||||
session.msg("%s\r\n%s" % (
|
||||
target_obj.get_name(fullname=True),
|
||||
target_obj.get_description(no_parsing=True),
|
||||
))
|
||||
session.msg("Type: %s Flags: %s" % (target_obj.get_type(), target_obj.get_flags()))
|
||||
session.msg("Owner: %s " % (target_obj.get_owner(),))
|
||||
session.msg("Zone: %s" % (target_obj.get_zone(),))
|
||||
|
||||
for attribute in target_obj.get_all_attributes():
|
||||
session.msg(attribute.get_attrline())
|
||||
|
||||
con_players = []
|
||||
con_things = []
|
||||
con_exits = []
|
||||
|
||||
for obj in target_obj.get_contents():
|
||||
if obj.is_player():
|
||||
con_players.append(obj)
|
||||
elif obj.is_exit():
|
||||
con_exits.append(obj)
|
||||
elif obj.is_thing():
|
||||
con_things.append(obj)
|
||||
|
||||
if con_players or con_things:
|
||||
session.msg("%sContents:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
|
||||
for player in con_players:
|
||||
session.msg('%s' % (player.get_name(fullname=True),))
|
||||
for thing in con_things:
|
||||
session.msg('%s' % (thing.get_name(fullname=True),))
|
||||
|
||||
if con_exits:
|
||||
session.msg("%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],))
|
||||
for exit in con_exits:
|
||||
session.msg('%s' %(exit.get_name(fullname=True),))
|
||||
|
||||
if not target_obj.is_room():
|
||||
if target_obj.is_exit():
|
||||
session.msg("Destination: %s" % (target_obj.get_home(),))
|
||||
else:
|
||||
session.msg("Home: %s" % (target_obj.get_home(),))
|
||||
|
||||
session.msg("Location: %s" % (target_obj.get_location(),))
|
||||
|
||||
def cmd_page(cdat):
|
||||
"""
|
||||
Send a message to target user (if online).
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
parsed_command = cdat['uinput']['parsed_command']
|
||||
# We use a dict to ensure that the list of targets is unique
|
||||
targets = dict()
|
||||
# Get the last paged person
|
||||
last_paged_dbrefs = pobject.get_attribute_value("LASTPAGED")
|
||||
# If they have paged someone before, go ahead and grab the object of
|
||||
# that person.
|
||||
if last_paged_dbrefs is not False:
|
||||
last_paged_objects = list()
|
||||
try:
|
||||
last_paged_dbref_list = [
|
||||
x.strip() for x in last_paged_dbrefs.split(',')]
|
||||
for dbref in last_paged_dbref_list:
|
||||
if not Object.objects.is_dbref(dbref):
|
||||
raise ValueError
|
||||
last_paged_object = Object.objects.dbref_search(dbref)
|
||||
if last_paged_object is not None:
|
||||
last_paged_objects.append(last_paged_object)
|
||||
except ValueError:
|
||||
# LASTPAGED Attribute is not a list of dbrefs
|
||||
last_paged_dbrefs = False
|
||||
# Remove the invalid LASTPAGED attribute
|
||||
pobject.clear_attribute("LASTPAGED")
|
||||
|
||||
# If they don't give a target, or any data to send to the target
|
||||
# then tell them who they last paged if they paged someone, if not
|
||||
# tell them they haven't paged anyone.
|
||||
if parsed_command['targets'] is None and parsed_command['data'] is None:
|
||||
if last_paged_dbrefs is not False and not last_paged_objects == list():
|
||||
session.msg("You last paged: %s." % (
|
||||
', '.join([x.name for x in last_paged_objects])))
|
||||
return
|
||||
session.msg("You have not paged anyone.")
|
||||
return
|
||||
|
||||
# Build a list of targets
|
||||
# If there are no targets, then set the targets to the last person they
|
||||
# paged.
|
||||
if parsed_command['targets'] is None:
|
||||
if not last_paged_objects == list():
|
||||
targets = dict([(target, 1) for target in last_paged_objects])
|
||||
else:
|
||||
# First try to match the entire target string against a single player
|
||||
full_target_match = Object.objects.player_name_search(
|
||||
parsed_command['original_targets'])
|
||||
if full_target_match is not None:
|
||||
targets[full_target_match] = 1
|
||||
else:
|
||||
# For each of the targets listed, grab their objects and append
|
||||
# it to the targets list
|
||||
for target in parsed_command['targets']:
|
||||
# If the target is a dbref, behave appropriately
|
||||
if Object.objects.is_dbref(target):
|
||||
session.msg("Is dbref.")
|
||||
matched_object = Object.objects.dbref_search(target,
|
||||
limit_types=[defines_global.OTYPE_PLAYER])
|
||||
if matched_object is not None:
|
||||
targets[matched_object] = 1
|
||||
else:
|
||||
# search returned None
|
||||
session.msg("Player '%s' does not exist." % (
|
||||
target))
|
||||
else:
|
||||
# Not a dbref, so must be a username, treat it as such
|
||||
matched_object = Object.objects.player_name_search(
|
||||
target)
|
||||
if matched_object is not None:
|
||||
targets[matched_object] = 1
|
||||
else:
|
||||
# search returned None
|
||||
session.msg("Player '%s' does not exist." % (
|
||||
target))
|
||||
data = parsed_command['data']
|
||||
sender_name = pobject.get_name(show_dbref=False)
|
||||
# Build our messages
|
||||
target_message = "%s pages: %s"
|
||||
sender_message = "You paged %s with '%s'."
|
||||
# Handle paged emotes
|
||||
if data.startswith(':'):
|
||||
data = data[1:]
|
||||
target_message = "From afar, %s %s"
|
||||
sender_message = "Long distance to %s: %s %s"
|
||||
# Handle paged emotes without spaces
|
||||
if data.startswith(';'):
|
||||
data = data[1:]
|
||||
target_message = "From afar, %s%s"
|
||||
sender_message = "Long distance to %s: %s%s"
|
||||
|
||||
# We build a list of target_names for the sender_message later
|
||||
target_names = []
|
||||
for target in targets.keys():
|
||||
# Check to make sure they're connected, or a player
|
||||
if target.is_connected_plr():
|
||||
target.emit_to(target_message % (sender_name, data))
|
||||
target_names.append(target.get_name(show_dbref=False))
|
||||
else:
|
||||
session.msg("Player %s does not exist or is not online." % (
|
||||
target.get_name(show_dbref=False)))
|
||||
|
||||
if len(target_names) > 0:
|
||||
target_names_string = ', '.join(target_names)
|
||||
try:
|
||||
session.msg(sender_message % (target_names_string, sender_name, data))
|
||||
except TypeError:
|
||||
session.msg(sender_message % (target_names_string, data))
|
||||
# Now set the LASTPAGED attribute
|
||||
pobject.set_attribute("LASTPAGED", ','.join(
|
||||
["#%d" % (x.id) for x in targets.keys()]))
|
||||
|
||||
def cmd_quit(cdat):
|
||||
"""
|
||||
Gracefully disconnect the user as per his own request.
|
||||
"""
|
||||
session = cdat['session']
|
||||
session.msg("Quitting!")
|
||||
session.handle_close()
|
||||
|
||||
def cmd_who(cdat):
|
||||
"""
|
||||
Generic WHO command.
|
||||
"""
|
||||
session_list = session_mgr.get_session_list()
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
show_session_data = pobject.user_has_perm("genperms.see_session_data")
|
||||
|
||||
# Only those with the see_session_data or superuser status can see
|
||||
# session details.
|
||||
if show_session_data:
|
||||
retval = "Player Name On For Idle Room Cmds Host\n\r"
|
||||
else:
|
||||
retval = "Player Name On For Idle\n\r"
|
||||
|
||||
for player in session_list:
|
||||
if not player.logged_in:
|
||||
continue
|
||||
delta_cmd = time.time() - player.cmd_last_visible
|
||||
delta_conn = time.time() - player.conn_time
|
||||
plr_pobject = player.get_pobject()
|
||||
|
||||
if show_session_data:
|
||||
retval += '%-16s%9s %4s%-3s#%-6d%5d%3s%-25s\r\n' % \
|
||||
(plr_pobject.get_name(show_dbref=False)[:25].ljust(27), \
|
||||
# On-time
|
||||
functions_general.time_format(delta_conn,0), \
|
||||
# Idle time
|
||||
functions_general.time_format(delta_cmd,1), \
|
||||
# Flags
|
||||
'', \
|
||||
# Location
|
||||
plr_pobject.get_location().id, \
|
||||
player.cmd_total, \
|
||||
# More flags?
|
||||
'', \
|
||||
player.address[0])
|
||||
else:
|
||||
retval += '%-16s%9s %4s%-3s\r\n' % \
|
||||
(plr_pobject.get_name(show_dbref=False)[:25].ljust(27), \
|
||||
# On-time
|
||||
functions_general.time_format(delta_conn,0), \
|
||||
# Idle time
|
||||
functions_general.time_format(delta_cmd,1), \
|
||||
# Flags
|
||||
'')
|
||||
retval += '%d Players logged in.' % (len(session_list),)
|
||||
|
||||
session.msg(retval)
|
||||
|
||||
def cmd_say(cdat):
|
||||
"""
|
||||
Room-based speech command.
|
||||
"""
|
||||
session = cdat['session']
|
||||
|
||||
if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 1, errortext="Say what?"):
|
||||
return
|
||||
|
||||
session_list = session_mgr.get_session_list()
|
||||
pobject = session.get_pobject()
|
||||
speech = ' '.join(cdat['uinput']['splitted'][1:])
|
||||
|
||||
players_present = [player for player in session_list if player.get_pobject().get_location() == session.get_pobject().get_location() and player != session]
|
||||
|
||||
retval = "You say, '%s'" % (speech,)
|
||||
for player in players_present:
|
||||
player.msg("%s says, '%s'" % (pobject.get_name(show_dbref=False), speech,))
|
||||
|
||||
session.msg(retval)
|
||||
|
||||
def cmd_pose(cdat):
|
||||
"""
|
||||
Pose/emote command.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
switches = cdat['uinput']['root_chunk'][1:]
|
||||
|
||||
if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 1, errortext="Do what?"):
|
||||
return
|
||||
|
||||
session_list = session_mgr.get_session_list()
|
||||
speech = ' '.join(cdat['uinput']['splitted'][1:])
|
||||
|
||||
if "nospace" in switches:
|
||||
sent_msg = "%s%s" % (pobject.get_name(show_dbref=False), speech)
|
||||
else:
|
||||
sent_msg = "%s %s" % (pobject.get_name(show_dbref=False), speech)
|
||||
|
||||
players_present = [player for player in session_list if player.get_pobject().get_location() == session.get_pobject().get_location()]
|
||||
|
||||
for player in players_present:
|
||||
player.msg(sent_msg)
|
||||
|
||||
def cmd_help(cdat):
|
||||
"""
|
||||
Help system commands.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
topicstr = ' '.join(cdat['uinput']['splitted'][1:])
|
||||
|
||||
if len(topicstr) == 0:
|
||||
topicstr = "Help Index"
|
||||
elif len(topicstr) < 2 and not topicstr.isdigit():
|
||||
session.msg("Your search query is too short. It must be at least three letters long.")
|
||||
return
|
||||
|
||||
topics = HelpEntry.objects.find_topicmatch(pobject, topicstr)
|
||||
|
||||
if len(topics) == 0:
|
||||
session.msg("No matching topics found, please refine your search.")
|
||||
suggestions = HelpEntry.objects.find_topicsuggestions(pobject, topicstr)
|
||||
if len(suggestions) > 0:
|
||||
session.msg("Matching similarly named topics:")
|
||||
for result in suggestions:
|
||||
session.msg(" %s" % (result,))
|
||||
session.msg("You may type 'help <#>' to see any of these topics.")
|
||||
elif len(topics) > 1:
|
||||
session.msg("More than one match found:")
|
||||
for result in topics:
|
||||
session.msg("%3d. %s" % (result.id, result.get_topicname()))
|
||||
session.msg("You may type 'help <#>' to see any of these topics.")
|
||||
else:
|
||||
topic = topics[0]
|
||||
session.msg("\r\n%s%s%s" % (ansi.ansi["hilite"], topic.get_topicname(), ansi.ansi["normal"]))
|
||||
session.msg(topic.get_entrytext_ingame())
|
||||
111
src/commands/info.py
Normal file
111
src/commands/info.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
"""
|
||||
Commands that are generally staff-oriented that show information regarding
|
||||
the server instance.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
|
||||
import functions_general
|
||||
|
||||
if not functions_general.host_os_is('nt'):
|
||||
# Don't import the resource module if the host OS is Windows.
|
||||
import resource
|
||||
|
||||
import django
|
||||
|
||||
from apps.objects.models import Object
|
||||
from src import scheduler
|
||||
import defines_global
|
||||
|
||||
def cmd_version(cdat):
|
||||
"""
|
||||
Version info command.
|
||||
"""
|
||||
session = cdat['session']
|
||||
retval = "-"*50 +"\n\r"
|
||||
retval += " Evennia %s\n\r" % (defines_global.EVENNIA_VERSION,)
|
||||
retval += " Django %s\n\r" % (django.get_version())
|
||||
retval += "-"*50
|
||||
session.msg(retval)
|
||||
|
||||
def cmd_time(cdat):
|
||||
"""
|
||||
Server local time.
|
||||
"""
|
||||
session = cdat['session']
|
||||
session.msg('Current server time : %s' % (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),)))
|
||||
|
||||
def cmd_uptime(cdat):
|
||||
"""
|
||||
Server uptime and stats.
|
||||
"""
|
||||
session = cdat['session']
|
||||
server = cdat['server']
|
||||
start_delta = time.time() - server.start_time
|
||||
loadavg = os.getloadavg()
|
||||
session.msg('Current server time : %s' % (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),)))
|
||||
session.msg('Server start time : %s' % (time.strftime('%a %b %d %H:%M %Y', time.localtime(server.start_time),)))
|
||||
session.msg('Server uptime : %s' % functions_general.time_format(start_delta, style=2))
|
||||
session.msg('Server load (1 min) : %.2f' % loadavg[0])
|
||||
|
||||
def cmd_list(cdat):
|
||||
"""
|
||||
Shows some game related information.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
argstr = ''.join(args)
|
||||
|
||||
msg_invalid = "Unknown option. Use one of: commands, flags, process"
|
||||
|
||||
if len(argstr) == 0:
|
||||
session.msg(msg_invalid)
|
||||
elif argstr == "commands":
|
||||
session.msg('Commands: '+ ' '.join(session.server.command_list()))
|
||||
elif argstr == "process":
|
||||
if not functions_general.host_os_is('nt'):
|
||||
loadvg = os.getloadavg()
|
||||
psize = resource.getpagesize()
|
||||
rusage = resource.getrusage(resource.RUSAGE_SELF)
|
||||
session.msg("Process ID: %10d %10d bytes per page" % (os.getpid(), psize))
|
||||
session.msg("Time used: %10d user %10d sys" % (rusage[0],rusage[1]))
|
||||
session.msg("Integral mem:%10d shared %10d private%10d stack" % (rusage[3], rusage[4], rusage[5]))
|
||||
session.msg("Max res mem: %10d pages %10d bytes" % (rusage[2],rusage[2] * psize))
|
||||
session.msg("Page faults: %10d hard %10d soft %10d swapouts" % (rusage[7], rusage[6], rusage[8]))
|
||||
session.msg("Disk I/O: %10d reads %10d writes" % (rusage[9], rusage[10]))
|
||||
session.msg("Network I/O: %10d in %10d out" % (rusage[12], rusage[11]))
|
||||
session.msg("Context swi: %10d vol %10d forced %10d sigs" % (rusage[14], rusage[15], rusage[13]))
|
||||
else:
|
||||
session.msg("Feature not available on Windows.")
|
||||
return
|
||||
elif argstr == "flags":
|
||||
session.msg("Flags: "+" ".join(defines_global.SERVER_FLAGS))
|
||||
else:
|
||||
session.msg(msg_invalid)
|
||||
|
||||
def cmd_ps(cdat):
|
||||
"""
|
||||
Shows the process/event table.
|
||||
"""
|
||||
session = cdat['session']
|
||||
session.msg("-- Interval Events --")
|
||||
for event in scheduler.schedule:
|
||||
session.msg(" [%d/%d] %s" % (scheduler.get_event_nextfire(event),
|
||||
scheduler.get_event_interval(event),
|
||||
scheduler.get_event_description(event)))
|
||||
session.msg("Totals: %d interval events" % (len(scheduler.schedule),))
|
||||
|
||||
def cmd_stats(cdat):
|
||||
"""
|
||||
Shows stats about the database.
|
||||
4012 objects = 144 rooms, 212 exits, 613 things, 1878 players. (1165 garbage)
|
||||
"""
|
||||
session = cdat['session']
|
||||
stats_dict = Object.objects.object_totals()
|
||||
session.msg("%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" % (stats_dict["objects"],
|
||||
stats_dict["rooms"],
|
||||
stats_dict["exits"],
|
||||
stats_dict["things"],
|
||||
stats_dict["players"],
|
||||
stats_dict["garbage"]))
|
||||
547
src/commands/objmanip.py
Normal file
547
src/commands/objmanip.py
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
"""
|
||||
These commands typically are to do with building or modifying Objects.
|
||||
"""
|
||||
from apps.objects.models import Object
|
||||
# We'll import this as the full path to avoid local variable clashes.
|
||||
import src.flags
|
||||
from src import ansi
|
||||
from src import session_mgr
|
||||
|
||||
def cmd_teleport(cdat):
|
||||
"""
|
||||
Teleports an object somewhere.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Teleport where/what?")
|
||||
return
|
||||
|
||||
eq_args = args[0].split('=')
|
||||
search_str = ''.join(args)
|
||||
|
||||
# If we have more than one entry in our '=' delimited argument list,
|
||||
# then we're doing a @tel <victim>=<location>. If not, we're doing
|
||||
# a direct teleport, @tel <destination>.
|
||||
if len(eq_args) > 1:
|
||||
# Equal sign teleport.
|
||||
victim = Object.objects.standard_plr_objsearch(session, eq_args[0])
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not victim:
|
||||
return
|
||||
|
||||
destination = Object.objects.standard_plr_objsearch(session, eq_args[1])
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not destination:
|
||||
return
|
||||
|
||||
if victim.is_room():
|
||||
session.msg("You can't teleport a room.")
|
||||
return
|
||||
|
||||
if victim == destination:
|
||||
session.msg("You can't teleport an object inside of itself!")
|
||||
return
|
||||
session.msg("Teleported.")
|
||||
victim.move_to(destination)
|
||||
|
||||
# This is somewhat kludgy right now, we'll have to find a better way
|
||||
# to do it sometime else. If we can find a session in the server's
|
||||
# session list matching the object we're teleporting, force it to
|
||||
# look. This is going to typically be a player.
|
||||
victim_session = session_mgr.session_from_object(victim)
|
||||
if victim_session:
|
||||
victim_session.execute_cmd("look")
|
||||
|
||||
else:
|
||||
# Direct teleport (no equal sign)
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, search_str)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if target_obj == pobject:
|
||||
session.msg("You can't teleport inside yourself!")
|
||||
return
|
||||
session.msg("Teleported.")
|
||||
pobject.move_to(target_obj)
|
||||
session.execute_cmd("look")
|
||||
|
||||
def cmd_stats(cdat):
|
||||
"""
|
||||
Shows stats about the database.
|
||||
4012 objects = 144 rooms, 212 exits, 613 things, 1878 players. (1165 garbage)
|
||||
"""
|
||||
session = cdat['session']
|
||||
stats_dict = Object.objects.object_totals()
|
||||
session.msg("%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" % (stats_dict["objects"],
|
||||
stats_dict["rooms"],
|
||||
stats_dict["exits"],
|
||||
stats_dict["things"],
|
||||
stats_dict["players"],
|
||||
stats_dict["garbage"]))
|
||||
|
||||
def cmd_alias(cdat):
|
||||
"""
|
||||
Assigns an alias to a player object for ease of paging, etc.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Alias whom?")
|
||||
return
|
||||
|
||||
# Resplit the args on = to check for an almost-required =
|
||||
eq_args = ' '.join(args).split('=')
|
||||
|
||||
if len(eq_args) < 2:
|
||||
session.msg("Alias missing.")
|
||||
return
|
||||
|
||||
target = Object.objects.standard_plr_objsearch(session, eq_args[0])
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target:
|
||||
session.msg("Alias whom?")
|
||||
return
|
||||
|
||||
duplicates = Object.objects.player_alias_search(pobject, eq_args[1])
|
||||
|
||||
if duplicates:
|
||||
session.msg("Alias '%s' already exists." % (eq_args[1],))
|
||||
return
|
||||
else:
|
||||
if pobject.controls_other(target):
|
||||
target.set_attribute('ALIAS', eq_args[1])
|
||||
session.msg("Alias '%s' set for %s." % (eq_args[1], target.get_name()))
|
||||
else:
|
||||
session.msg("You do not have access to set an alias for %s." % (target.get_name(),))
|
||||
|
||||
def cmd_wipe(cdat):
|
||||
"""
|
||||
Wipes an object's attributes, or optionally only those matching a search
|
||||
string.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
attr_search = False
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Wipe what?")
|
||||
return
|
||||
|
||||
# Look for a slash in the input, indicating an attribute wipe.
|
||||
attr_split = args[0].split("/")
|
||||
|
||||
# If the splitting by the "/" character returns a list with more than 1
|
||||
# entry, it's an attribute match.
|
||||
if len(attr_split) > 1:
|
||||
attr_search = True
|
||||
# Strip the object search string from the input with the
|
||||
# object/attribute pair.
|
||||
searchstr = attr_split[0]
|
||||
# Just in case there's a slash in an attribute name.
|
||||
attr_searchstr = '/'.join(attr_split[1:])
|
||||
else:
|
||||
searchstr = ' '.join(args)
|
||||
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, searchstr)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if attr_search:
|
||||
# User has passed an attribute wild-card string. Search for name matches
|
||||
# and wipe.
|
||||
attr_matches = target_obj.attribute_namesearch(attr_searchstr, exclude_noset=True)
|
||||
if attr_matches:
|
||||
for attr in attr_matches:
|
||||
target_obj.clear_attribute(attr.get_name())
|
||||
session.msg("%s - %d attributes wiped." % (target_obj.get_name(), len(attr_matches)))
|
||||
else:
|
||||
session.msg("No matching attributes found.")
|
||||
else:
|
||||
# User didn't specify a wild-card string, wipe entire object.
|
||||
attr_matches = target_obj.attribute_namesearch("*", exclude_noset=True)
|
||||
for attr in attr_matches:
|
||||
target_obj.clear_attribute(attr.get_name())
|
||||
session.msg("%s - %d attributes wiped." % (target_obj.get_name(), len(attr_matches)))
|
||||
|
||||
def cmd_set(cdat):
|
||||
"""
|
||||
Sets flags or attributes on objects.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Set what?")
|
||||
return
|
||||
|
||||
# There's probably a better way to do this. Break the arguments (minus
|
||||
# the root command) up so we have two items in the list, 0 being the victim,
|
||||
# 1 being the list of flags or the attribute/value pair.
|
||||
eq_args = ' '.join(args).split('=')
|
||||
|
||||
if len(eq_args) < 2:
|
||||
session.msg("Set what?")
|
||||
return
|
||||
|
||||
victim = Object.objects.standard_plr_objsearch(session, eq_args[0])
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not victim:
|
||||
return
|
||||
|
||||
if not pobject.controls_other(victim):
|
||||
session.msg(defines_global.NOCONTROL_MSG)
|
||||
return
|
||||
|
||||
attrib_args = eq_args[1].split(':')
|
||||
|
||||
if len(attrib_args) > 1:
|
||||
# We're dealing with an attribute/value pair.
|
||||
attrib_name = attrib_args[0].upper()
|
||||
splicenum = eq_args[1].find(':') + 1
|
||||
attrib_value = eq_args[1][splicenum:]
|
||||
|
||||
# In global_defines.py, see NOSET_ATTRIBS for protected attribute names.
|
||||
if not src.flags.is_modifiable_attrib(attrib_name) and not pobject.is_superuser():
|
||||
session.msg("You can't modify that attribute.")
|
||||
return
|
||||
|
||||
if attrib_value:
|
||||
# An attribute value was specified, create or set the attribute.
|
||||
verb = 'set'
|
||||
victim.set_attribute(attrib_name, attrib_value)
|
||||
else:
|
||||
# No value was given, this means we delete the attribute.
|
||||
verb = 'cleared'
|
||||
victim.clear_attribute(attrib_name)
|
||||
session.msg("%s - %s %s." % (victim.get_name(), attrib_name, verb))
|
||||
else:
|
||||
# Flag manipulation form.
|
||||
flag_list = eq_args[1].split()
|
||||
|
||||
for flag in flag_list:
|
||||
flag = flag.upper()
|
||||
if flag[0] == '!':
|
||||
# We're un-setting the flag.
|
||||
flag = flag[1:]
|
||||
if not src.flags.is_modifiable_flag(flag):
|
||||
session.msg("You can't set/unset the flag - %s." % (flag,))
|
||||
else:
|
||||
session.msg('%s - %s cleared.' % (victim.get_name(), flag.upper(),))
|
||||
victim.set_flag(flag, False)
|
||||
else:
|
||||
# We're setting the flag.
|
||||
if not src.flags.is_modifiable_flag(flag):
|
||||
session.msg("You can't set/unset the flag - %s." % (flag,))
|
||||
else:
|
||||
session.msg('%s - %s set.' % (victim.get_name(), flag.upper(),))
|
||||
victim.set_flag(flag, True)
|
||||
|
||||
def cmd_find(cdat):
|
||||
"""
|
||||
Searches for an object of a particular name.
|
||||
"""
|
||||
session = cdat['session']
|
||||
server = cdat['server']
|
||||
searchstring = ' '.join(cdat['uinput']['splitted'][1:])
|
||||
pobject = session.get_pobject()
|
||||
can_find = pobject.user_has_perm("genperms.builder")
|
||||
|
||||
if searchstring == '':
|
||||
session.msg("No search pattern given.")
|
||||
return
|
||||
|
||||
results = Object.objects.global_object_name_search(searchstring)
|
||||
|
||||
if len(results) > 0:
|
||||
session.msg("Name matches for: %s" % (searchstring,))
|
||||
for result in results:
|
||||
session.msg(" %s" % (result.get_name(fullname=True),))
|
||||
session.msg("%d matches returned." % (len(results),))
|
||||
else:
|
||||
session.msg("No name matches found for: %s" % (searchstring,))
|
||||
|
||||
def cmd_create(cdat):
|
||||
"""
|
||||
Creates a new object of type 'THING'.
|
||||
"""
|
||||
session = cdat['session']
|
||||
server = session.server
|
||||
pobject = session.get_pobject()
|
||||
uinput= cdat['uinput']['splitted']
|
||||
thingname = ' '.join(uinput[1:])
|
||||
|
||||
if thingname == '':
|
||||
session.msg("You must supply a name!")
|
||||
else:
|
||||
# Create and set the object up.
|
||||
odat = {"name": thingname, "type": 3, "location": pobject, "owner": pobject}
|
||||
new_object = Object.objects.create_object(odat)
|
||||
|
||||
session.msg("You create a new thing: %s" % (new_object,))
|
||||
|
||||
def cmd_nextfree(cdat):
|
||||
"""
|
||||
Returns the next free object number.
|
||||
"""
|
||||
session = cdat['session']
|
||||
|
||||
nextfree = Object.objects.get_nextfree_dbnum()
|
||||
session.msg("Next free object number: #%s" % (nextfree,))
|
||||
|
||||
def cmd_open(cdat):
|
||||
"""
|
||||
Handle the opening of exits.
|
||||
|
||||
Forms:
|
||||
@open <Name>
|
||||
@open <Name>=<Dbref>
|
||||
@open <Name>=<Dbref>,<Name>
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Open an exit to where?")
|
||||
return
|
||||
|
||||
eq_args = ' '.join(args).split('=')
|
||||
exit_name = eq_args[0]
|
||||
|
||||
if len(exit_name) == 0:
|
||||
session.msg("You must supply an exit name.")
|
||||
return
|
||||
|
||||
# If we have more than one entry in our '=' delimited argument list,
|
||||
# then we're doing a @open <Name>=<Dbref>[,<Name>]. If not, we're doing
|
||||
# an un-linked exit, @open <Name>.
|
||||
if len(eq_args) > 1:
|
||||
# Opening an exit to another location via @open <Name>=<Dbref>[,<Name>].
|
||||
comma_split = eq_args[1].split(',')
|
||||
destination = Object.objects.standard_plr_objsearch(session, comma_split[0])
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not destination:
|
||||
return
|
||||
|
||||
if destination.is_exit():
|
||||
session.msg("You can't open an exit to an exit!")
|
||||
return
|
||||
|
||||
odat = {"name": exit_name, "type": 4, "location": pobject.get_location(), "owner": pobject, "home":destination}
|
||||
new_object = Object.objects.create_object(odat)
|
||||
|
||||
session.msg("You open the an exit - %s to %s" % (new_object.get_name(),destination.get_name()))
|
||||
|
||||
if len(comma_split) > 1:
|
||||
second_exit_name = ','.join(comma_split[1:])
|
||||
odat = {"name": second_exit_name, "type": 4, "location": destination, "owner": pobject, "home": pobject.get_location()}
|
||||
new_object = Object.objects.create_object(odat)
|
||||
session.msg("You open the an exit - %s to %s" % (new_object.get_name(),pobject.get_location().get_name()))
|
||||
|
||||
else:
|
||||
# Create an un-linked exit.
|
||||
odat = {"name": exit_name, "type": 4, "location": pobject.get_location(), "owner": pobject, "home":None}
|
||||
new_object = Object.objects.create_object(odat)
|
||||
|
||||
session.msg("You open an unlinked exit - %s" % (new_object,))
|
||||
|
||||
def cmd_link(cdat):
|
||||
"""
|
||||
Sets an object's home or an exit's destination.
|
||||
|
||||
Forms:
|
||||
@link <Object>=<Target>
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
server = cdat['server']
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Link what?")
|
||||
return
|
||||
|
||||
eq_args = args[0].split('=')
|
||||
target_name = eq_args[0]
|
||||
dest_name = '='.join(eq_args[1:])
|
||||
|
||||
if len(target_name) == 0:
|
||||
session.msg("What do you want to link?")
|
||||
return
|
||||
|
||||
if len(eq_args) > 1:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, target_name)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if not pobject.controls_other(target_obj):
|
||||
session.msg(defines_global.NOCONTROL_MSG)
|
||||
return
|
||||
|
||||
# If we do something like "@link blah=", we unlink the object.
|
||||
if len(dest_name) == 0:
|
||||
target_obj.set_home(None)
|
||||
session.msg("You have unlinked %s." % (target_obj,))
|
||||
return
|
||||
|
||||
destination = Object.objects.standard_plr_objsearch(session, dest_name)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not destination:
|
||||
return
|
||||
|
||||
target_obj.set_home(destination)
|
||||
session.msg("You link %s to %s." % (target_obj,destination))
|
||||
|
||||
else:
|
||||
# We haven't provided a target.
|
||||
session.msg("You must provide a destination to link to.")
|
||||
return
|
||||
|
||||
def cmd_unlink(cdat):
|
||||
"""
|
||||
Unlinks an object.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Unlink what?")
|
||||
return
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args))
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if not pobject.controls_other(target_obj):
|
||||
session.msg(defines_global.NOCONTROL_MSG)
|
||||
return
|
||||
|
||||
target_obj.set_home(None)
|
||||
session.msg("You have unlinked %s." % (target_obj.get_name(),))
|
||||
|
||||
def cmd_dig(cdat):
|
||||
"""
|
||||
Creates a new object of type 'ROOM'.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
uinput= cdat['uinput']['splitted']
|
||||
roomname = ' '.join(uinput[1:])
|
||||
|
||||
if roomname == '':
|
||||
session.msg("You must supply a name!")
|
||||
else:
|
||||
# Create and set the object up.
|
||||
odat = {"name": roomname, "type": 2, "location": None, "owner": pobject}
|
||||
new_object = Object.objects.create_object(odat)
|
||||
|
||||
session.msg("You create a new room: %s" % (new_object,))
|
||||
|
||||
def cmd_name(cdat):
|
||||
"""
|
||||
Handle naming an object.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
eq_args = ' '.join(args).split('=')
|
||||
searchstring = ''.join(eq_args[0])
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("What do you want to name?")
|
||||
elif len(eq_args) < 2:
|
||||
session.msg("What would you like to name that object?")
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, searchstring)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if len(eq_args[1]) == 0:
|
||||
session.msg("What would you like to name that object?")
|
||||
else:
|
||||
newname = '='.join(eq_args[1:])
|
||||
session.msg("You have renamed %s to %s." % (target_obj, ansi.parse_ansi(newname, strip_formatting=True)))
|
||||
target_obj.set_name(newname)
|
||||
|
||||
def cmd_description(cdat):
|
||||
"""
|
||||
Set an object's description.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
eq_args = ' '.join(args).split('=')
|
||||
searchstring = ''.join(eq_args[0])
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("What do you want to describe?")
|
||||
elif len(eq_args) < 2:
|
||||
session.msg("How would you like to describe that object?")
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, searchstring)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if not pobject.controls_other(target_obj):
|
||||
session.msg(defines_global.NOCONTROL_MSG)
|
||||
return
|
||||
|
||||
new_desc = '='.join(eq_args[1:])
|
||||
session.msg("%s - DESCRIPTION set." % (target_obj,))
|
||||
target_obj.set_description(new_desc)
|
||||
|
||||
def cmd_destroy(cdat):
|
||||
"""
|
||||
Destroy an object.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
switches = cdat['uinput']['root_chunk'][1:]
|
||||
switch_override = False
|
||||
|
||||
if "override" in switches:
|
||||
switch_override = True
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Destroy what?")
|
||||
return
|
||||
else:
|
||||
target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args))
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if target_obj.is_player():
|
||||
if pobject.id == target_obj.id:
|
||||
session.msg("You can't destroy yourself.")
|
||||
return
|
||||
if not switch_override:
|
||||
session.msg("You must use @destroy/override on players.")
|
||||
return
|
||||
if target_obj.is_superuser():
|
||||
session.msg("You can't destroy a superuser.")
|
||||
return
|
||||
elif target_obj.is_going() or target_obj.is_garbage():
|
||||
session.msg("That object is already destroyed.")
|
||||
return
|
||||
|
||||
session.msg("You destroy %s." % (target_obj.get_name(),))
|
||||
target_obj.destroy()
|
||||
130
src/commands/privileged.py
Normal file
130
src/commands/privileged.py
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
from apps.objects.models import Object
|
||||
import defines_global
|
||||
import functions_general
|
||||
from src import ansi
|
||||
|
||||
"""
|
||||
This file contains commands that require special permissions to use. These
|
||||
are generally @-prefixed commands, but there are exceptions.
|
||||
"""
|
||||
|
||||
def cmd_reload(cdat):
|
||||
"""
|
||||
Reloads all modules.
|
||||
"""
|
||||
session = cdat['session']
|
||||
server = session.server.reload(session)
|
||||
|
||||
def cmd_boot(cdat):
|
||||
"""
|
||||
Boot a player object from the server.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
eq_args = ' '.join(args).split('=')
|
||||
searchstring = ''.join(eq_args[0])
|
||||
switches = cdat['uinput']['root_chunk'][1:]
|
||||
switch_quiet = False
|
||||
switch_port = False
|
||||
|
||||
if not pobject.is_staff():
|
||||
session.msg("You do not have permission to do that.")
|
||||
return
|
||||
|
||||
if "quiet" in switches:
|
||||
switch_quiet = True
|
||||
|
||||
if "port" in switches:
|
||||
switch_port = True
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("Who would you like to boot?")
|
||||
return
|
||||
else:
|
||||
boot_list = []
|
||||
if switch_port:
|
||||
sessions = session_mgr.get_session_list(True)
|
||||
for sess in sessions:
|
||||
if sess.getClientAddress()[1] == int(searchstring):
|
||||
boot_list.append(sess)
|
||||
# We're done here
|
||||
break
|
||||
else:
|
||||
# Grab the objects that match
|
||||
objs = Objects.object.global_object_name_search(searchstring)
|
||||
|
||||
if len(objs) < 1:
|
||||
session.msg("Who would you like to boot?")
|
||||
return
|
||||
|
||||
if not objs[0].is_player():
|
||||
session.msg("You can only boot players.")
|
||||
return
|
||||
|
||||
if not pobject.controls_other(objs[0]):
|
||||
if objs[0].is_superuser():
|
||||
session.msg("You cannot boot a Wizard.")
|
||||
return
|
||||
else:
|
||||
session.msg("You do not have permission to boot that player.")
|
||||
return
|
||||
|
||||
if objs[0].is_connected_plr():
|
||||
boot_list.append(session_mgr.session_from_object(objs[0]))
|
||||
|
||||
for boot in boot_list:
|
||||
if not switch_quiet:
|
||||
boot.msg("You have been disconnected by %s." % (pobject.name))
|
||||
boot.disconnectClient()
|
||||
session_mgr.remove_session(boot)
|
||||
return
|
||||
|
||||
def cmd_newpassword(cdat):
|
||||
"""
|
||||
Set a player's password.
|
||||
"""
|
||||
session = cdat['session']
|
||||
pobject = session.get_pobject()
|
||||
args = cdat['uinput']['splitted'][1:]
|
||||
eq_args = ' '.join(args).split('=')
|
||||
searchstring = ''.join(eq_args[0])
|
||||
newpass = ''.join(eq_args[1:])
|
||||
|
||||
if len(args) == 0:
|
||||
session.msg("What player's password do you want to change")
|
||||
return
|
||||
if len(newpass) == 0:
|
||||
session.msg("You must supply a new password.")
|
||||
return
|
||||
|
||||
target_obj = Objects.object.standard_plr_objsearch(session, searchstring)
|
||||
# Use standard_plr_objsearch to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
if not target_obj.is_player():
|
||||
session.msg("You can only change passwords on players.")
|
||||
elif not pobject.controls_other(target_obj):
|
||||
session.msg("You do not control %s." % (target_obj.get_name(),))
|
||||
else:
|
||||
uaccount = target_obj.get_user_account()
|
||||
if len(newpass) == 0:
|
||||
uaccount.set_password()
|
||||
else:
|
||||
uaccount.set_password(newpass)
|
||||
uaccount.save()
|
||||
session.msg("%s - PASSWORD set." % (target_obj.get_name(),))
|
||||
target_obj.emit_to("%s has changed your password." % (pobject.get_name(show_dbref=False),))
|
||||
|
||||
def cmd_shutdown(cdat):
|
||||
"""
|
||||
Shut the server down gracefully.
|
||||
"""
|
||||
session = cdat['session']
|
||||
server = cdat['server']
|
||||
pobject = session.get_pobject()
|
||||
|
||||
session.msg('Shutting down...')
|
||||
print 'Server shutdown by %s' % (pobject.get_name(show_dbref=False),)
|
||||
server.shutdown()
|
||||
97
src/commands/unloggedin.py
Normal file
97
src/commands/unloggedin.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
"""
|
||||
Commands that are available from the connect screen.
|
||||
"""
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from apps.objects.models import Attribute, Object
|
||||
import functions_general
|
||||
import defines_global
|
||||
|
||||
def cmd_connect(cdat):
|
||||
"""
|
||||
This is the connect command at the connection screen. Fairly simple,
|
||||
uses the Django database API and User model to make it extremely simple.
|
||||
"""
|
||||
|
||||
session = cdat['session']
|
||||
|
||||
# Argument check.
|
||||
if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 2):
|
||||
return
|
||||
|
||||
uemail = cdat['uinput']['splitted'][1]
|
||||
password = cdat['uinput']['splitted'][2]
|
||||
|
||||
# Match an email address to an account.
|
||||
email_matches = Object.objects.get_user_from_email(uemail)
|
||||
|
||||
autherror = "Specified email does not match any accounts!"
|
||||
# No username match
|
||||
if email_matches.count() == 0:
|
||||
session.msg(autherror)
|
||||
return
|
||||
|
||||
# We have at least one result, so we can check the password.
|
||||
user = email_matches[0]
|
||||
|
||||
if not user.check_password(password):
|
||||
session.msg(autherror)
|
||||
else:
|
||||
uname = user.username
|
||||
session.login(user)
|
||||
|
||||
def cmd_create(cdat):
|
||||
"""
|
||||
Handle the creation of new accounts.
|
||||
"""
|
||||
session = cdat['session']
|
||||
|
||||
# Argument check.
|
||||
if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 2):
|
||||
return
|
||||
|
||||
server = session.server
|
||||
quote_split = ' '.join(cdat['uinput']['splitted']).split("\"")
|
||||
|
||||
if len(quote_split) < 2:
|
||||
session.msg("You must enclose your username in quotation marks.")
|
||||
return
|
||||
|
||||
uname = quote_split[1]
|
||||
lastarg_split = quote_split[2].split()
|
||||
|
||||
if len(lastarg_split) != 2:
|
||||
session.msg("You must specify an email address, followed by a password!")
|
||||
return
|
||||
|
||||
email = lastarg_split[0]
|
||||
password = lastarg_split[1]
|
||||
|
||||
# Search for a user object with the specified username.
|
||||
account = User.objects.filter(username=uname)
|
||||
# Match an email address to an account.
|
||||
email_matches = Object.objects.get_user_from_email(email)
|
||||
# Look for any objects with an 'Alias' attribute that matches
|
||||
# the requested username
|
||||
alias_matches = Object.objects.filter(attribute__attr_name__exact="ALIAS",
|
||||
attribute__attr_value__iexact=uname).filter(
|
||||
type=defines_global.OTYPE_PLAYER)
|
||||
|
||||
if not account.count() == 0 or not alias_matches.count() == 0:
|
||||
session.msg("There is already a player with that name!")
|
||||
elif not email_matches.count() == 0:
|
||||
session.msg("There is already a player with that email address!")
|
||||
elif len(password) < 3:
|
||||
session.msg("Your password must be 3 characters or longer.")
|
||||
else:
|
||||
Object.objects.create_user(cdat, uname, email, password)
|
||||
|
||||
def cmd_quit(cdat):
|
||||
"""
|
||||
We're going to maintain a different version of the quit command
|
||||
here for unconnected users for the sake of simplicity. The logged in
|
||||
version will be a bit more complicated.
|
||||
"""
|
||||
session = cdat['session']
|
||||
session.msg("Disconnecting...")
|
||||
session.handle_close()
|
||||
11
src/events.py
Normal file
11
src/events.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import session_mgr
|
||||
|
||||
"""
|
||||
Holds the events scheduled in scheduler.py.
|
||||
"""
|
||||
|
||||
def evt_check_sessions():
|
||||
"""
|
||||
Event: Check all of the connected sessions.
|
||||
"""
|
||||
session_mgr.check_all_sessions()
|
||||
18
src/initial_setup.py
Normal file
18
src/initial_setup.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from django.contrib.auth.models import User, Group
|
||||
from apps.objects.models import Object
|
||||
from apps.config.models import ConfigValue
|
||||
|
||||
def handle_setup():
|
||||
# Set the initial user's username on the #1 object.
|
||||
god_user = User.objects.filter(id=1)[0]
|
||||
god_user_obj = Object.objects.filter(id=1)[0]
|
||||
god_user_obj.set_name(god_user.username)
|
||||
|
||||
groups = ("Immortals", "Wizards", "Builders", "Player Helpers")
|
||||
for group in groups:
|
||||
newgroup = Group()
|
||||
newgroup.name = group
|
||||
newgroup.save()
|
||||
|
||||
# We don't want to do initial setup tasks every startup, only the first.
|
||||
ConfigValue.objects.set_configvalue('game_firstrun', '0')
|
||||
108
src/scheduler.py
Normal file
108
src/scheduler.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import time
|
||||
from twisted.internet import task
|
||||
from src import events
|
||||
"""
|
||||
This file contains the event scheduler system.
|
||||
|
||||
ADDING AN EVENT:
|
||||
* Create an event function to call.
|
||||
* Add an entry to the 'schedule' dictionary here.
|
||||
* Profit.
|
||||
"""
|
||||
|
||||
# Dictionary of events with a list in the form of:
|
||||
# [<function>, <interval>, <lastrantime>, <taskobject>, <description>]
|
||||
schedule = {
|
||||
'evt_check_sessions': [events.evt_check_sessions, 60, time.time(), None, "Session consistency checks."]
|
||||
}
|
||||
|
||||
def start_events():
|
||||
"""
|
||||
Start the event system, which is built on Twisted's framework.
|
||||
"""
|
||||
for event in schedule:
|
||||
event_func = get_event_function(event)
|
||||
|
||||
if callable(event_func):
|
||||
# Set the call-back function for the task to trigger_event, but pass
|
||||
# a reference to the event function.
|
||||
event_task = task.LoopingCall(trigger_event, event_func, event)
|
||||
# Start the task up with the specified interval.
|
||||
event_task.start(get_event_interval(event), now=False)
|
||||
# Set a reference to the event's task object in the dictionary so we
|
||||
# can re-schedule, start, and stop events from elsewhere.
|
||||
set_event_taskobj(event, event_task)
|
||||
|
||||
def get_event(event_name):
|
||||
"""
|
||||
Return the relevant entry in the schedule dictionary for the named event.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
return schedule.get(event_name, None)
|
||||
|
||||
def get_event_function(event_name):
|
||||
"""
|
||||
Return a reference to the event's function.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
return get_event(event_name)[0]
|
||||
|
||||
def get_event_interval(event_name):
|
||||
"""
|
||||
Return the event's execution interval.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
return get_event(event_name)[1]
|
||||
|
||||
def get_event_nextfire(event_name):
|
||||
"""
|
||||
Returns a value in seconds when the event is going to fire off next.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
return (get_event(event_name)[2]+get_event_interval(event_name))-time.time()
|
||||
|
||||
def get_event_taskobj(event_name):
|
||||
"""
|
||||
Returns an event's task object.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
return get_event(event_name)[3]
|
||||
|
||||
def get_event_description(event_name):
|
||||
"""
|
||||
Returns an event's description.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
return get_event(event_name)[4]
|
||||
|
||||
def set_event_taskobj(event_name, taskobj):
|
||||
"""
|
||||
Sets an event's task object.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
get_event(event_name)[3] = taskobj
|
||||
|
||||
def set_event_lastfired(event_name):
|
||||
"""
|
||||
Sets an event's last fired time.
|
||||
|
||||
event_name: (string) The key of the event in the schedule dictionary.
|
||||
"""
|
||||
get_event(event_name)[2] = time.time()
|
||||
|
||||
def trigger_event(event_func, event_name):
|
||||
"""
|
||||
Update the last ran time and fire off the event.
|
||||
|
||||
event_func: (func_reference) Reference to the event function to fire.
|
||||
eventname: (string) The name of the event (as per schedule dict).
|
||||
"""
|
||||
event_func()
|
||||
set_event_lastfired(event_name)
|
||||
68
src/scripthandler.py
Normal file
68
src/scripthandler.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
"""
|
||||
This module is responsible for managing scripts and their connection to the
|
||||
Object class model. It is important to keep this as independent from the
|
||||
codebase as possible in order to allow for drop-in replacements. All
|
||||
interaction with actual script methods should happen via calls to Objects.
|
||||
"""
|
||||
import os
|
||||
from traceback import format_exc
|
||||
|
||||
import settings
|
||||
import functions_log
|
||||
|
||||
# A dictionary with keys equivalent to the script's name and values that
|
||||
# contain references to the associated module for each key.
|
||||
cached_scripts = {}
|
||||
|
||||
def scriptlink(source_obj, scriptname):
|
||||
"""
|
||||
Each Object will refer to this function when trying to execute a function
|
||||
contained within a scripted module. For the sake of ease of management,
|
||||
modules are cached and compiled as they are requested and stored in
|
||||
the cached_scripts dictionary.
|
||||
|
||||
Returns a reference to an instance of the script's class as per it's
|
||||
class_factory() method.
|
||||
|
||||
source_obj: (Object) A reference to the object being scripted.
|
||||
scriptname: (str) Name of the module to load (minus 'scripts').
|
||||
"""
|
||||
# The module is already cached, just return it rather than re-load.
|
||||
retval = cached_scripts.get(scriptname, False)
|
||||
if retval:
|
||||
return retval.class_factory(source_obj)
|
||||
|
||||
##
|
||||
## NOTE: Only go past here when the script isn't already cached.
|
||||
##
|
||||
|
||||
# Split the script name up by periods to give us the directory we need
|
||||
# to change to. I really wish we didn't have to do this, but there's some
|
||||
# strange issue with __import__ and more than two directories worth of
|
||||
# nesting.
|
||||
path_split = scriptname.split('.')
|
||||
newpath_str = '/'.join(path_split[:-1])
|
||||
# Lop the module name off the end.
|
||||
modname = path_split[-1]
|
||||
|
||||
try:
|
||||
# Change the working directory to the location of the script and import.
|
||||
os.chdir('%s/%s/' % (settings.SCRIPT_ROOT, newpath_str))
|
||||
functions_log.log_infomsg("SCRIPT: Caching and importing %s." % (modname))
|
||||
modreference = __import__(modname)
|
||||
# Store the module reference for later fast retrieval.
|
||||
cached_scripts[scriptname] = modreference
|
||||
except ImportError:
|
||||
functions_log.log_infomsg('Error importing %s: %s' % (modname, format_exc()))
|
||||
os.chdir(settings.BASE_PATH)
|
||||
return
|
||||
except OSError:
|
||||
functions_log.log_infomsg('Invalid module path: %s' % (format_exc()))
|
||||
os.chdir(settings.BASE_PATH)
|
||||
return
|
||||
|
||||
# Change back to the original working directory.
|
||||
os.chdir(settings.BASE_PATH)
|
||||
|
||||
# The new script module has been cached, return the reference.
|
||||
return modreference.class_factory(source_obj)
|
||||
0
src/scripts/__init__.py
Normal file
0
src/scripts/__init__.py
Normal file
142
src/scripts/basicobject.py
Normal file
142
src/scripts/basicobject.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
"""
|
||||
This will be the base object type/interface that all scripts are derived from by
|
||||
default. It will have the necessary outline for developers to sub-class and override.
|
||||
"""
|
||||
from src import ansi
|
||||
|
||||
class BasicObject:
|
||||
def __init__(self, source_obj):
|
||||
"""
|
||||
Get our ducks in a row.
|
||||
|
||||
source_obj: (Object) A reference to the object being scripted (the child).
|
||||
"""
|
||||
self.source_obj = source_obj
|
||||
|
||||
def a_desc(self, values):
|
||||
"""
|
||||
Perform this action when someone uses the LOOK command on the object.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
# Un-comment the line below for an example
|
||||
#print "SCRIPT TEST: %s looked at %s." % (values["pobject"], self.source_obj)
|
||||
pass
|
||||
|
||||
def return_appearance(self, values):
|
||||
"""
|
||||
Returns a string representation of an object's appearance when LOOKed at.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
target_obj = self.source_obj
|
||||
pobject = values["pobject"]
|
||||
description = target_obj.get_description()
|
||||
if description is not None:
|
||||
retval = "%s\r\n%s" % (
|
||||
target_obj.get_name(),
|
||||
target_obj.get_description(),
|
||||
)
|
||||
else:
|
||||
retval = "%s" % (
|
||||
target_obj.get_name(),
|
||||
)
|
||||
|
||||
con_players = []
|
||||
con_things = []
|
||||
con_exits = []
|
||||
|
||||
for obj in target_obj.get_contents():
|
||||
if obj.is_player():
|
||||
if obj != pobject and obj.is_connected_plr():
|
||||
con_players.append(obj)
|
||||
elif obj.is_exit():
|
||||
con_exits.append(obj)
|
||||
else:
|
||||
con_things.append(obj)
|
||||
|
||||
if not con_players == []:
|
||||
retval += "\n\r%sPlayers:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)
|
||||
for player in con_players:
|
||||
retval +='\n\r%s' %(player.get_name(),)
|
||||
if not con_things == []:
|
||||
retval += "\n\r%sContents:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)
|
||||
for thing in con_things:
|
||||
retval += '\n\r%s' %(thing.get_name(),)
|
||||
if not con_exits == []:
|
||||
retval += "\n\r%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)
|
||||
for exit in con_exits:
|
||||
retval += '\n\r%s' %(exit.get_name(),)
|
||||
|
||||
return retval
|
||||
|
||||
def a_get(self, values):
|
||||
"""
|
||||
Perform this action when someone uses the GET command on the object.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
# Un-comment the line below for an example
|
||||
#print "SCRIPT TEST: %s got %s." % (values["pobject"], self.source_obj)
|
||||
pass
|
||||
|
||||
def a_drop(self, values):
|
||||
"""
|
||||
Perform this action when someone uses the GET command on the object.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
# Un-comment the line below for an example
|
||||
#print "SCRIPT TEST: %s dropped %s." % (values["pobject"], self.source_obj)
|
||||
pass
|
||||
|
||||
def default_lock(self, values):
|
||||
"""
|
||||
This method returns a True or False boolean value to determine whether
|
||||
the actor passes the lock. This is generally used for picking up
|
||||
objects or traversing exits.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
# Assume everyone passes the default lock by default.
|
||||
return True
|
||||
|
||||
def use_lock(self, values):
|
||||
"""
|
||||
This method returns a True or False boolean value to determine whether
|
||||
the actor passes the lock. This is generally used for seeing whether
|
||||
a player can use an object or any of its commands.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
# Assume everyone passes the use lock by default.
|
||||
return True
|
||||
|
||||
def enter_lock(self, values):
|
||||
"""
|
||||
This method returns a True or False boolean value to determine whether
|
||||
the actor passes the lock. This is generally used for seeing whether
|
||||
a player can enter another object.
|
||||
|
||||
values: (Dict) Script arguments with keys:
|
||||
* pobject: The object requesting the action.
|
||||
"""
|
||||
# Assume everyone passes the enter lock by default.
|
||||
return True
|
||||
|
||||
def class_factory(source_obj):
|
||||
"""
|
||||
This method is called any script you retrieve (via the scripthandler). It
|
||||
creates an instance of the class and returns it transparently. I'm not
|
||||
sure how well this will scale, but we'll find out. We may need to
|
||||
re-factor this eventually.
|
||||
|
||||
source_obj: (Object) A reference to the object being scripted (the child).
|
||||
"""
|
||||
return BasicObject(source_obj)
|
||||
0
src/scripts/exit/__init__.py
Normal file
0
src/scripts/exit/__init__.py
Normal file
0
src/scripts/npc/__init__.py
Normal file
0
src/scripts/npc/__init__.py
Normal file
0
src/scripts/thing/__init__.py
Normal file
0
src/scripts/thing/__init__.py
Normal file
121
src/server.py
Executable file
121
src/server.py
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
from traceback import format_exc
|
||||
import time, sys
|
||||
|
||||
from twisted.application import internet, service
|
||||
from twisted.internet import protocol, reactor, defer
|
||||
from twisted.python import log
|
||||
|
||||
from django.db import models
|
||||
from django.db import connection
|
||||
from django.conf import settings
|
||||
|
||||
from apps.config.models import CommandAlias, ConfigValue
|
||||
from src.session import SessionProtocol
|
||||
from src import scheduler
|
||||
import functions_general
|
||||
from src import session_mgr
|
||||
from src import cmdtable
|
||||
from src import initial_setup
|
||||
|
||||
class EvenniaService(service.Service):
|
||||
|
||||
def __init__(self, filename="blah"):
|
||||
self.cmd_alias_list = {}
|
||||
self.game_running = True
|
||||
sys.path.append('.')
|
||||
|
||||
# Database-specific startup optimizations.
|
||||
if settings.DATABASE_ENGINE == "sqlite3":
|
||||
self.sqlite3_prep()
|
||||
|
||||
# Wipe our temporary flags on all of the objects.
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("UPDATE objects_object SET nosave_flags=''")
|
||||
|
||||
print '-'*50
|
||||
# Load command aliases into memory for easy/quick access.
|
||||
self.load_cmd_aliases()
|
||||
|
||||
if ConfigValue.objects.get_configvalue('game_firstrun') == '1':
|
||||
print ' Game started for the first time, setting defaults.'
|
||||
initial_setup.handle_setup()
|
||||
|
||||
self.start_time = time.time()
|
||||
|
||||
print ' %s started on port(s):' % (ConfigValue.objects.get_configvalue('site_name'),)
|
||||
for port in settings.GAMEPORTS:
|
||||
print ' * %s' % (port)
|
||||
print '-'*50
|
||||
scheduler.start_events()
|
||||
|
||||
"""
|
||||
BEGIN SERVER STARTUP METHODS
|
||||
"""
|
||||
def load_cmd_aliases(self):
|
||||
"""
|
||||
Load up our command aliases.
|
||||
"""
|
||||
alias_list = CommandAlias.objects.all()
|
||||
for alias in alias_list:
|
||||
self.cmd_alias_list[alias.user_input] = alias.equiv_command
|
||||
print ' Command Aliases Loaded: %i' % (len(self.cmd_alias_list),)
|
||||
pass
|
||||
|
||||
def sqlite3_prep(self):
|
||||
"""
|
||||
Optimize some SQLite stuff at startup since we can't save it to the
|
||||
database.
|
||||
"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("PRAGMA cache_size=10000")
|
||||
cursor.execute("PRAGMA synchronous=OFF")
|
||||
cursor.execute("PRAGMA count_changes=OFF")
|
||||
cursor.execute("PRAGMA temp_store=2")
|
||||
|
||||
"""
|
||||
BEGIN GENERAL METHODS
|
||||
"""
|
||||
def shutdown(self, message='The server has been shutdown. Please check back soon.'):
|
||||
functions_general.announce_all(message)
|
||||
session_mgr.disconnect_all_sessions()
|
||||
reactor.callLater(0, reactor.stop)
|
||||
|
||||
def command_list(self):
|
||||
"""
|
||||
Return a string representing the server's command list.
|
||||
"""
|
||||
clist = cmdtable.ctable.keys()
|
||||
clist.sort()
|
||||
return clist
|
||||
|
||||
def reload(self, session):
|
||||
"""
|
||||
Reload modules that don't have any variables that can be reset.
|
||||
For changes to the scheduler, server, or session_mgr modules, a cold
|
||||
restart is needed.
|
||||
"""
|
||||
reload_list = []
|
||||
|
||||
for mod in reload_list:
|
||||
reload(sys.modules[mod])
|
||||
|
||||
session.msg("Modules reloaded.")
|
||||
functions_general.log_infomsg("Modules reloaded by %s." % (session,))
|
||||
|
||||
def getEvenniaServiceFactory(self):
|
||||
f = protocol.ServerFactory()
|
||||
f.protocol = SessionProtocol
|
||||
f.server = self
|
||||
return f
|
||||
|
||||
"""
|
||||
END Server CLASS
|
||||
"""
|
||||
|
||||
application = service.Application('Evennia')
|
||||
mud_service = EvenniaService('Evennia Server')
|
||||
|
||||
# Sheet sheet, fire ze missiles!
|
||||
serviceCollection = service.IServiceCollection(application)
|
||||
for port in settings.GAMEPORTS:
|
||||
internet.TCPServer(port, mud_service.getEvenniaServiceFactory()).setServiceParent(serviceCollection)
|
||||
186
src/session.py
Executable file
186
src/session.py
Executable file
|
|
@ -0,0 +1,186 @@
|
|||
"""
|
||||
This module contains classes related to Sessions. session_mgr has the things
|
||||
needed to manage them.
|
||||
"""
|
||||
import time
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from twisted.conch.telnet import StatefulTelnetProtocol
|
||||
|
||||
from django.utils import simplejson
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from apps.objects.models import Object
|
||||
from apps.config.models import ConnectScreen, ConfigValue
|
||||
import cmdhandler
|
||||
import functions_general
|
||||
import functions_log
|
||||
import session_mgr
|
||||
import ansi
|
||||
|
||||
class SessionProtocol(StatefulTelnetProtocol):
|
||||
"""
|
||||
This class represents a player's sesssion. From here we branch down into
|
||||
other various classes, please try to keep this one tidy!
|
||||
"""
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
What to do when we get a connection.
|
||||
"""
|
||||
self.prep_session()
|
||||
functions_log.log_infomsg('Connection: %s' % (self,))
|
||||
session_mgr.add_session(self)
|
||||
self.game_connect_screen()
|
||||
|
||||
def getClientAddress(self):
|
||||
"""
|
||||
Returns the client's address and port in a tuple. For example
|
||||
('127.0.0.1', 41917)
|
||||
"""
|
||||
return self.transport.client
|
||||
|
||||
def prep_session(self):
|
||||
self.server = self.factory.server
|
||||
self.address = self.getClientAddress()
|
||||
self.name = None
|
||||
self.uid = None
|
||||
self.logged_in = False
|
||||
# The time the user last issued a command.
|
||||
self.cmd_last = time.time()
|
||||
# Player-visible idle time, excluding the IDLE command.
|
||||
self.cmd_last_visible = time.time()
|
||||
# Total number of commands issued.
|
||||
self.cmd_total = 0
|
||||
# The time when the user connected.
|
||||
self.conn_time = time.time()
|
||||
self.channels_subscribed = {}
|
||||
|
||||
def disconnectClient(self):
|
||||
"""
|
||||
Manually disconnect the client.
|
||||
"""
|
||||
self.transport.loseConnection()
|
||||
|
||||
def connectionLost(self, reason):
|
||||
"""
|
||||
Execute this when a client abruplty loses their connection.
|
||||
"""
|
||||
functions_log.log_infomsg('Disconnect: %s' % (self,))
|
||||
self.handle_close()
|
||||
|
||||
def load_user_channels(self):
|
||||
"""
|
||||
Parse JSON dict of a user's channel list from their CHANLIST attribute.
|
||||
"""
|
||||
chan_list = self.get_pobject().get_attribute_value("__CHANLIST")
|
||||
if chan_list:
|
||||
self.channels_subscribed = simplejson.loads(chan_list)
|
||||
|
||||
def lineReceived(self, data):
|
||||
"""
|
||||
Any line return indicates a command for the purpose of a MUD. So we take
|
||||
the user input and pass it to our command handler.
|
||||
"""
|
||||
line = (''.join(data))
|
||||
line = line.strip('\r')
|
||||
uinput = line
|
||||
|
||||
# Stuff anything we need to pass in this dictionary.
|
||||
cdat = {"server": self.factory.server, "uinput": uinput, "session": self}
|
||||
cmdhandler.handle(cdat)
|
||||
|
||||
def execute_cmd(self, cmdstr):
|
||||
"""
|
||||
Executes a command as this session.
|
||||
"""
|
||||
self.lineReceived(data=cmdstr)
|
||||
|
||||
def handle_close(self):
|
||||
"""
|
||||
Break the connection and do some accounting.
|
||||
"""
|
||||
pobject = self.get_pobject()
|
||||
if pobject:
|
||||
pobject.set_flag("CONNECTED", False)
|
||||
pobject.get_location().emit_to_contents("%s has disconnected." % (pobject.get_name(show_dbref=False),), exclude=pobject)
|
||||
uaccount = pobject.get_user_account()
|
||||
uaccount.last_login = datetime.now()
|
||||
uaccount.save()
|
||||
|
||||
self.disconnectClient()
|
||||
self.logged_in = False
|
||||
session_mgr.remove_session(self)
|
||||
|
||||
def get_pobject(self):
|
||||
"""
|
||||
Returns the object associated with a session.
|
||||
"""
|
||||
try:
|
||||
result = Object.objects.get(id=self.uid)
|
||||
return result
|
||||
except:
|
||||
return False
|
||||
|
||||
def game_connect_screen(self):
|
||||
"""
|
||||
Show the banner screen. Grab from the 'connect_screen' config directive.
|
||||
"""
|
||||
screen = ConnectScreen.objects.get_random_connect_screen()
|
||||
buffer = ansi.parse_ansi(screen.connect_screen_text)
|
||||
self.msg(buffer)
|
||||
|
||||
def is_loggedin(self):
|
||||
"""
|
||||
Returns a boolean True if the session is logged in.
|
||||
"""
|
||||
try:
|
||||
return self.logged_in
|
||||
except:
|
||||
return False
|
||||
|
||||
def login(self, user):
|
||||
"""
|
||||
After the user has authenticated, handle logging him in.
|
||||
"""
|
||||
self.uid = user.id
|
||||
self.name = user.username
|
||||
self.logged_in = True
|
||||
self.conn_time = time.time()
|
||||
pobject = self.get_pobject()
|
||||
session_mgr.disconnect_duplicate_session(self)
|
||||
pobject.set_flag("CONNECTED", True)
|
||||
|
||||
self.msg("You are now logged in as %s." % (self.name,))
|
||||
pobject.get_location().emit_to_contents("%s has connected." % (pobject.get_name(show_dbref=False),), exclude=pobject)
|
||||
self.execute_cmd("look")
|
||||
functions_log.log_infomsg("Login: %s" % (self,))
|
||||
|
||||
# Update their account's last login time.
|
||||
user.last_login = datetime.now()
|
||||
user.save()
|
||||
pobject.set_attribute("Last", "%s" % (time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()),))
|
||||
pobject.set_attribute("Lastsite", "%s" % (self.address[0],))
|
||||
|
||||
# Load their channel selection from a JSON-encoded string attribute.
|
||||
self.load_user_channels()
|
||||
|
||||
def msg(self, message):
|
||||
"""
|
||||
Sends a message to the session.
|
||||
"""
|
||||
if isinstance(message, unicode):
|
||||
message = message.encode("utf-8")
|
||||
self.sendLine("%s" % (message,))
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
String representation of the user session class. We use
|
||||
this a lot in the server logs and stuff.
|
||||
"""
|
||||
if self.is_loggedin():
|
||||
symbol = '#'
|
||||
else:
|
||||
symbol = '?'
|
||||
return "<%s> %s@%s" % (symbol, self.name, self.address,)
|
||||
104
src/session_mgr.py
Normal file
104
src/session_mgr.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
"""
|
||||
Session manager, handles connected players.
|
||||
"""
|
||||
import time
|
||||
|
||||
from apps.config.models import ConfigValue
|
||||
import functions_general
|
||||
import functions_log
|
||||
|
||||
# Our list of connected sessions.
|
||||
session_list = []
|
||||
|
||||
def add_session(session):
|
||||
"""
|
||||
Adds a session to the session list.
|
||||
"""
|
||||
session_list.insert(0, session)
|
||||
functions_log.log_infomsg('Sessions active: %d' % (len(get_session_list(return_unlogged=True),)))
|
||||
|
||||
def get_session_list(return_unlogged=False):
|
||||
"""
|
||||
Lists the connected session objects.
|
||||
"""
|
||||
if return_unlogged:
|
||||
return session_list
|
||||
else:
|
||||
return [sess for sess in session_list if sess.is_loggedin()]
|
||||
|
||||
def disconnect_all_sessions():
|
||||
"""
|
||||
Cleanly disconnect all of the connected sessions.
|
||||
"""
|
||||
for sess in get_session_list():
|
||||
sess.handle_close()
|
||||
|
||||
def disconnect_duplicate_session(session):
|
||||
"""
|
||||
Disconnects any existing session under the same object. This is used in
|
||||
connection recovery to help with record-keeping.
|
||||
"""
|
||||
sess_list = get_session_list()
|
||||
new_pobj = session.get_pobject()
|
||||
for sess in sess_list:
|
||||
if new_pobj == sess.get_pobject() and sess != session:
|
||||
sess.msg("Your account has been logged in from elsewhere, disconnecting.")
|
||||
sess.disconnectClient()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def check_all_sessions():
|
||||
"""
|
||||
Check all currently connected sessions and see if any are dead.
|
||||
"""
|
||||
idle_timeout = int(ConfigValue.objects.get_configvalue('idle_timeout'))
|
||||
|
||||
if len(session_list) <= 0:
|
||||
return
|
||||
|
||||
if idle_timeout <= 0:
|
||||
return
|
||||
|
||||
for sess in get_session_list(return_unlogged=True):
|
||||
if (time.time() - sess.cmd_last) > idle_timeout:
|
||||
sess.msg("Idle timeout exceeded, disconnecting.")
|
||||
sess.handle_close()
|
||||
|
||||
def remove_session(session):
|
||||
"""
|
||||
Removes a session from the session list.
|
||||
"""
|
||||
try:
|
||||
session_list.remove(session)
|
||||
functions_log.log_infomsg('Sessions active: %d' % (len(get_session_list()),))
|
||||
except ValueError:
|
||||
#functions_log.log_errmsg("Unable to remove session: %s" % (session,))
|
||||
pass
|
||||
|
||||
|
||||
def session_from_object(targobject):
|
||||
"""
|
||||
Return the session object given a object (if there is one open).
|
||||
|
||||
session_list: (list) The server's session_list attribute.
|
||||
targobject: (Object) The object to match.
|
||||
"""
|
||||
results = [prospect for prospect in session_list if prospect.get_pobject() == targobject]
|
||||
if results:
|
||||
return results[0]
|
||||
else:
|
||||
return False
|
||||
|
||||
def session_from_dbref(dbstring):
|
||||
"""
|
||||
Return the session object given a dbref (if there is one open).
|
||||
|
||||
dbstring: (int) The dbref number to match against.
|
||||
"""
|
||||
if is_dbref(dbstring):
|
||||
results = [prospect for prospect in session_list if prospect.get_pobject().dbref_match(dbstring)]
|
||||
if results:
|
||||
return results[0]
|
||||
else:
|
||||
return False
|
||||
Loading…
Add table
Add a link
Reference in a new issue