Run Migrate. Implemented a full separation between Player and Character - Players (OOC entities) can now also hold cmdsets and execute commands. This means that "disconnecting" from a Character becomes possible, putting the Player in an "OOC" state outside the game. This overall makes the game much more stable since there used to be issues if the character was destroyed. Having an OOC set also avoids the previous problem of @puppeting into an object that didn't have any cmdset of its own - you couldn't get back out! A new default OOC-Cmdset handles commands available to a player while OOC. Commands in this set are applied with a low priority, allowing "IC" mode to give precedence if desired.
This change meant several changes to the lock and permission functionality, since it becomes important if permissions are assigned on the Player or on their Character (lock functions pperm() and pid() etc check on Player rather than Character). This has the boon of allowing Admins to switch and play/test the game as a "Low access" character as they like. Plenty of bug fixes and adjustments. Migrations should make sure to move over all data properly.
This commit is contained in:
parent
ce2a8e9ffe
commit
28fe2ad3f4
37 changed files with 1622 additions and 555 deletions
|
|
@ -19,7 +19,7 @@ new cmdset class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from src.commands.cmdset import CmdSet
|
from src.commands.cmdset import CmdSet
|
||||||
from src.commands.default import cmdset_default, cmdset_unloggedin
|
from src.commands.default import cmdset_default, cmdset_unloggedin, cmdset_ooc
|
||||||
|
|
||||||
from game.gamesrc.commands.basecommand import Command
|
from game.gamesrc.commands.basecommand import Command
|
||||||
|
|
||||||
|
|
@ -70,6 +70,24 @@ class UnloggedinCmdSet(cmdset_unloggedin.UnloggedinCmdSet):
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class OOCCmdSet(cmdset_ooc.OOCCmdSet):
|
||||||
|
"""
|
||||||
|
This is set is available to the player when they have no
|
||||||
|
character connected to them (i.e. they are out-of-character, ooc).
|
||||||
|
"""
|
||||||
|
key = "OOC"
|
||||||
|
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
"""
|
||||||
|
Populates the cmdset
|
||||||
|
"""
|
||||||
|
super(OOCCmdSet, self).at_cmdset_creation()
|
||||||
|
|
||||||
|
#
|
||||||
|
# any commands you add below will overload the default ones.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
class BaseCmdSet(CmdSet):
|
class BaseCmdSet(CmdSet):
|
||||||
"""
|
"""
|
||||||
Implements an empty, example cmdset.
|
Implements an empty, example cmdset.
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,6 @@ class Object(BaseObject):
|
||||||
|
|
||||||
Hooks (these are class methods, so their arguments should also start with self):
|
Hooks (these are class methods, so their arguments should also start with self):
|
||||||
|
|
||||||
basetype_setup() - only called once, when object is first created, before
|
|
||||||
at_object_creation(). Sets up semi-engine-specific details such as
|
|
||||||
the default lock policy, what defines a Room, Exit etc.
|
|
||||||
Usually not modified unless you want to overload the default
|
|
||||||
security restriction policies.
|
|
||||||
|
|
||||||
at_object_creation() - only called once, when object is first created.
|
at_object_creation() - only called once, when object is first created.
|
||||||
Almost all object customizations go here.
|
Almost all object customizations go here.
|
||||||
at_first_login() - only called once, the very first time user logs in.
|
at_first_login() - only called once, the very first time user logs in.
|
||||||
|
|
|
||||||
|
|
@ -54,14 +54,11 @@ from django.conf import settings
|
||||||
from src.comms.channelhandler import CHANNELHANDLER
|
from src.comms.channelhandler import CHANNELHANDLER
|
||||||
from src.commands.cmdsethandler import import_cmdset
|
from src.commands.cmdsethandler import import_cmdset
|
||||||
from src.objects.exithandler import EXITHANDLER
|
from src.objects.exithandler import EXITHANDLER
|
||||||
from src.utils import logger
|
from src.utils import logger, utils
|
||||||
|
|
||||||
#This switches the command parser to a user-defined one.
|
#This switches the command parser to a user-defined one.
|
||||||
# You have to restart the server for this to take effect.
|
# You have to restart the server for this to take effect.
|
||||||
try:
|
COMMAND_PARSER = utils.mod_import(*settings.COMMAND_PARSER.rsplit('.', 1))
|
||||||
CMDPARSER = __import__(settings.ALTERNATE_PARSER, fromlist=[True]).cmdparser
|
|
||||||
except Exception:
|
|
||||||
from src.commands.cmdparser import cmdparser as CMDPARSER
|
|
||||||
|
|
||||||
# There are a few system-hardcoded command names. These
|
# There are a few system-hardcoded command names. These
|
||||||
# allow for custom behaviour when the command handler hits
|
# allow for custom behaviour when the command handler hits
|
||||||
|
|
@ -101,12 +98,20 @@ def get_and_merge_cmdsets(caller):
|
||||||
exit_cmdset = None
|
exit_cmdset = None
|
||||||
local_objects_cmdsets = [None]
|
local_objects_cmdsets = [None]
|
||||||
|
|
||||||
|
# Player object's commandsets
|
||||||
|
try:
|
||||||
|
player_cmdset = caller.player.cmdset.current
|
||||||
|
except AttributeError:
|
||||||
|
player_cmdset = None
|
||||||
|
|
||||||
if not caller_cmdset.no_channels:
|
if not caller_cmdset.no_channels:
|
||||||
# Make cmdsets out of all valid channels
|
# Make cmdsets out of all valid channels
|
||||||
channel_cmdset = CHANNELHANDLER.get_cmdset(caller)
|
channel_cmdset = CHANNELHANDLER.get_cmdset(caller)
|
||||||
if not caller_cmdset.no_exits:
|
if not caller_cmdset.no_exits:
|
||||||
# Make cmdsets out of all valid exits in the room
|
# Make cmdsets out of all valid exits in the room
|
||||||
exit_cmdset = EXITHANDLER.get_cmdset(caller)
|
exit_cmdset = EXITHANDLER.get_cmdset(caller)
|
||||||
|
location = None
|
||||||
|
if hasattr(caller, "location"):
|
||||||
location = caller.location
|
location = caller.location
|
||||||
if location and not caller_cmdset.no_objs:
|
if location and not caller_cmdset.no_objs:
|
||||||
# Gather all cmdsets stored on objects in the room and
|
# Gather all cmdsets stored on objects in the room and
|
||||||
|
|
@ -138,6 +143,12 @@ def get_and_merge_cmdsets(caller):
|
||||||
cmdset = channel_cmdset + cmdset
|
cmdset = channel_cmdset + cmdset
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
# finally merge on the player cmdset. This should have a low priority
|
||||||
|
try:
|
||||||
|
cmdset = player_cmdset + cmdset
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
|
||||||
return cmdset
|
return cmdset
|
||||||
|
|
||||||
def match_command(cmd_candidates, cmdset, logged_caller=None):
|
def match_command(cmd_candidates, cmdset, logged_caller=None):
|
||||||
|
|
@ -295,7 +306,7 @@ def cmdhandler(caller, raw_string, unloggedin=False, testing=False):
|
||||||
raise ExecSystemCommand(syscmd, sysarg)
|
raise ExecSystemCommand(syscmd, sysarg)
|
||||||
|
|
||||||
# Parse the input string into command candidates
|
# Parse the input string into command candidates
|
||||||
cmd_candidates = CMDPARSER(raw_string)
|
cmd_candidates = COMMAND_PARSER(raw_string)
|
||||||
|
|
||||||
#string ="Command candidates"
|
#string ="Command candidates"
|
||||||
#for cand in cmd_candidates:
|
#for cand in cmd_candidates:
|
||||||
|
|
|
||||||
|
|
@ -174,3 +174,128 @@ def cmdparser(raw_string):
|
||||||
wordlist = raw_string.split(" ")
|
wordlist = raw_string.split(" ")
|
||||||
candidates.extend(produce_candidates(nr_candidates, wordlist))
|
candidates.extend(produce_candidates(nr_candidates, wordlist))
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# Search parsers and support methods
|
||||||
|
#------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Default functions for formatting and processing searches.
|
||||||
|
#
|
||||||
|
# This is in its own module due to them being possible to
|
||||||
|
# replace from the settings file by setting the variables
|
||||||
|
#
|
||||||
|
# SEARCH_AT_RESULTERROR_HANDLER
|
||||||
|
# SEARCH_MULTIMATCH_PARSER
|
||||||
|
#
|
||||||
|
# The the replacing modules must have the same inputs and outputs as
|
||||||
|
# those in this module.
|
||||||
|
#
|
||||||
|
|
||||||
|
def at_search_result(msg_obj, ostring, results, global_search=False):
|
||||||
|
"""
|
||||||
|
Called by search methods after a result of any type has been found.
|
||||||
|
|
||||||
|
Takes a search result (a list) and
|
||||||
|
formats eventual errors.
|
||||||
|
|
||||||
|
msg_obj - object to receive feedback.
|
||||||
|
ostring - original search string
|
||||||
|
results - list of found matches (0, 1 or more)
|
||||||
|
global_search - if this was a global_search or not
|
||||||
|
(if it is, there might be an idea of supplying
|
||||||
|
dbrefs instead of only numbers)
|
||||||
|
|
||||||
|
Multiple matches are returned to the searching object
|
||||||
|
as
|
||||||
|
1-object
|
||||||
|
2-object
|
||||||
|
3-object
|
||||||
|
etc
|
||||||
|
|
||||||
|
"""
|
||||||
|
string = ""
|
||||||
|
if not results:
|
||||||
|
# no results.
|
||||||
|
string = "Could not find '%s'." % ostring
|
||||||
|
results = None
|
||||||
|
|
||||||
|
elif len(results) > 1:
|
||||||
|
# we have more than one match. We will display a
|
||||||
|
# list of the form 1-objname, 2-objname etc.
|
||||||
|
|
||||||
|
# check if the msg_object may se dbrefs
|
||||||
|
show_dbref = global_search
|
||||||
|
|
||||||
|
string += "More than one match for '%s'" % ostring
|
||||||
|
string += " (please narrow target):"
|
||||||
|
for num, result in enumerate(results):
|
||||||
|
invtext = ""
|
||||||
|
dbreftext = ""
|
||||||
|
if hasattr(result, "location") and result.location == msg_obj:
|
||||||
|
invtext = " (carried)"
|
||||||
|
if show_dbref:
|
||||||
|
dbreftext = "(#%i)" % result.id
|
||||||
|
string += "\n %i-%s%s%s" % (num+1, result.name,
|
||||||
|
dbreftext, invtext)
|
||||||
|
results = None
|
||||||
|
else:
|
||||||
|
# we have exactly one match.
|
||||||
|
results = results[0]
|
||||||
|
|
||||||
|
if string:
|
||||||
|
msg_obj.msg(string.strip())
|
||||||
|
return results
|
||||||
|
|
||||||
|
def at_multimatch_input(ostring):
|
||||||
|
"""
|
||||||
|
Parse number-identifiers.
|
||||||
|
|
||||||
|
This parser will be called by the engine when a user supplies
|
||||||
|
a search term. The search term must be analyzed to determine
|
||||||
|
if the user wants to differentiate between multiple matches
|
||||||
|
(usually found during a previous search).
|
||||||
|
|
||||||
|
This method should separate out any identifiers from the search
|
||||||
|
string used to differentiate between same-named objects. The
|
||||||
|
result should be a tuple (index, search_string) where the index
|
||||||
|
gives which match among multiple matches should be used (1 being
|
||||||
|
the lowest number, rather than 0 as in Python).
|
||||||
|
|
||||||
|
This parser version will identify search strings on the following
|
||||||
|
forms
|
||||||
|
|
||||||
|
2-object
|
||||||
|
|
||||||
|
This will be parsed to (2, "object") and, if applicable, will tell
|
||||||
|
the engine to pick the second from a list of same-named matches of
|
||||||
|
objects called "object".
|
||||||
|
|
||||||
|
Ex for use in a game session:
|
||||||
|
|
||||||
|
> look
|
||||||
|
You see: ball, ball, ball and ball.
|
||||||
|
> get ball
|
||||||
|
There where multiple matches for ball:
|
||||||
|
1-ball
|
||||||
|
2-ball
|
||||||
|
3-ball
|
||||||
|
4-ball
|
||||||
|
> get 3-ball
|
||||||
|
You get the ball.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(ostring, basestring):
|
||||||
|
return (None, ostring)
|
||||||
|
if not '-' in ostring:
|
||||||
|
return (None, ostring)
|
||||||
|
try:
|
||||||
|
index = ostring.find('-')
|
||||||
|
number = int(ostring[:index])-1
|
||||||
|
return (number, ostring[index+1:])
|
||||||
|
except ValueError:
|
||||||
|
#not a number; this is not an identifier.
|
||||||
|
return (None, ostring)
|
||||||
|
except IndexError:
|
||||||
|
return (None, ostring)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ together to create interesting in-game effects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
from src.utils.utils import inherits_from, is_iter
|
||||||
|
|
||||||
|
RECURSIVE_PROTECTION = False
|
||||||
|
|
||||||
class CmdSetMeta(type):
|
class CmdSetMeta(type):
|
||||||
"""
|
"""
|
||||||
|
|
@ -204,16 +207,40 @@ class CmdSet(object):
|
||||||
|
|
||||||
def add(self, cmd):
|
def add(self, cmd):
|
||||||
"""
|
"""
|
||||||
Add a command to this cmdset.
|
Add a command, a list of commands or a cmdset to this cmdset.
|
||||||
|
|
||||||
Note that if cmd already exists in set,
|
Note that if cmd already exists in set,
|
||||||
it will replace the old one (no priority checking etc
|
it will replace the old one (no priority checking etc
|
||||||
at this point; this is often used to overload
|
at this point; this is often used to overload
|
||||||
default commands).
|
default commands).
|
||||||
"""
|
|
||||||
cmd = instantiate(cmd)
|
|
||||||
|
|
||||||
if cmd:
|
If cmd is another cmdset class or -instance, the commands
|
||||||
|
of that command set is added to this one, as if they were part
|
||||||
|
of the original cmdset definition. No merging or priority checks
|
||||||
|
are made, rather later added commands will simply replace
|
||||||
|
existing ones to make a unique set.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if inherits_from(cmd, "src.commands.cmdset.CmdSet"):
|
||||||
|
# this is a command set so merge all commands in that set
|
||||||
|
# to this one. We are not protecting against recursive
|
||||||
|
# loops (adding a cmdset that itself adds this cmdset here
|
||||||
|
# since such an error will be very visible and lead to a
|
||||||
|
# traceback at startup anyway.
|
||||||
|
try:
|
||||||
|
cmd = instantiate(cmd)
|
||||||
|
except RuntimeError, e:
|
||||||
|
string = "Adding cmdset %s to %s lead to an infinite loop. When adding a cmdset to another, "
|
||||||
|
string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain."
|
||||||
|
raise RuntimeError(string % (cmd, self.__class__))
|
||||||
|
cmds = cmd.commands
|
||||||
|
elif not is_iter(cmd):
|
||||||
|
cmds = [instantiate(cmd)]
|
||||||
|
else:
|
||||||
|
cmds = instantiate(cmd)
|
||||||
|
|
||||||
|
for cmd in cmds:
|
||||||
|
# add all commands
|
||||||
if not hasattr(cmd, 'obj'):
|
if not hasattr(cmd, 'obj'):
|
||||||
cmd.obj = self.cmdsetobj
|
cmd.obj = self.cmdsetobj
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ class CmdSetHandler(object):
|
||||||
string += "\n"
|
string += "\n"
|
||||||
merged = True
|
merged = True
|
||||||
|
|
||||||
# Display the currently active cmdset
|
# Display the currently active cmdset, limited by self.obj's permissions
|
||||||
mergetype = self.mergetype_stack[-1]
|
mergetype = self.mergetype_stack[-1]
|
||||||
if mergetype != self.current.mergetype:
|
if mergetype != self.current.mergetype:
|
||||||
merged_on = self.cmdset_stack[-2].key
|
merged_on = self.cmdset_stack[-2].key
|
||||||
|
|
@ -187,7 +187,8 @@ class CmdSetHandler(object):
|
||||||
if merged:
|
if merged:
|
||||||
string += " <Merged (%s)>: %s" % (mergetype, self.current)
|
string += " <Merged (%s)>: %s" % (mergetype, self.current)
|
||||||
else:
|
else:
|
||||||
string += " <%s (%s)>: %s" % (self.current.key, mergetype, self.current)
|
string += " <%s (%s)>: %s" % (self.current.key, mergetype,
|
||||||
|
", ".join(cmd.key for cmd in self.current if cmd.access(self.obj, "cmd")))
|
||||||
return string.strip()
|
return string.strip()
|
||||||
|
|
||||||
def update(self, init_mode=False):
|
def update(self, init_mode=False):
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ class CmdBoot(MuxCommand):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# Boot by player object
|
# Boot by player object
|
||||||
pobj = caller.search("*%s" % args, global_search=True)
|
pobj = caller.search("*%s" % args, global_search=True, player=True)
|
||||||
if not pobj:
|
if not pobj:
|
||||||
return
|
return
|
||||||
if pobj.character.has_player:
|
if pobj.character.has_player:
|
||||||
|
|
@ -118,6 +118,9 @@ class CmdDelPlayer(MuxCommand):
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
args = self.args
|
args = self.args
|
||||||
|
|
||||||
|
if hasattr(caller, 'player'):
|
||||||
|
caller = caller.player
|
||||||
|
|
||||||
if not args:
|
if not args:
|
||||||
caller.msg("Usage: @delplayer[/delobj] <player/user name or #id> [: reason]")
|
caller.msg("Usage: @delplayer[/delobj] <player/user name or #id> [: reason]")
|
||||||
return
|
return
|
||||||
|
|
@ -128,7 +131,7 @@ class CmdDelPlayer(MuxCommand):
|
||||||
|
|
||||||
# We use player_search since we want to be sure to find also players
|
# We use player_search since we want to be sure to find also players
|
||||||
# that lack characters.
|
# that lack characters.
|
||||||
players = caller.search("*%s" % args)
|
players = caller.search("*%s" % args, player=True)
|
||||||
if not players:
|
if not players:
|
||||||
try:
|
try:
|
||||||
players = PlayerDB.objects.filter(id=args)
|
players = PlayerDB.objects.filter(id=args)
|
||||||
|
|
@ -304,7 +307,7 @@ class CmdNewPassword(MuxCommand):
|
||||||
return
|
return
|
||||||
|
|
||||||
# the player search also matches 'me' etc.
|
# the player search also matches 'me' etc.
|
||||||
player = caller.search("*%s" % self.lhs, global_search=True)
|
player = caller.search("*%s" % self.lhs, global_search=True, player=True)
|
||||||
if not player:
|
if not player:
|
||||||
return
|
return
|
||||||
player.user.set_password(self.rhs)
|
player.user.set_password(self.rhs)
|
||||||
|
|
@ -320,12 +323,14 @@ class CmdPerm(MuxCommand):
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@perm[/switch] <object> [= <permission>[,<permission>,...]]
|
@perm[/switch] <object> [= <permission>[,<permission>,...]]
|
||||||
|
@perm[/switch] *<player> [= <permission>[,<permission>,...]]
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
del : delete the given permission from <object>.
|
del : delete the given permission from <object> or <player>.
|
||||||
|
player : set permission on a player (same as adding * to name)
|
||||||
|
|
||||||
This command sets/clears individual permission strings on an object.
|
This command sets/clears individual permission strings on an object
|
||||||
If no permission is given, list all permissions on <object>
|
or player. If no permission is given, list all permissions on <object>.
|
||||||
"""
|
"""
|
||||||
key = "@perm"
|
key = "@perm"
|
||||||
aliases = "@setperm"
|
aliases = "@setperm"
|
||||||
|
|
@ -340,17 +345,18 @@ class CmdPerm(MuxCommand):
|
||||||
lhs, rhs = self.lhs, self.rhs
|
lhs, rhs = self.lhs, self.rhs
|
||||||
|
|
||||||
if not self.args:
|
if not self.args:
|
||||||
string = "Usage: @perm[/switch] object [ = permission, permission, ...]\n"
|
string = "Usage: @perm[/switch] object [ = permission, permission, ...]"
|
||||||
caller.msg(string)
|
caller.msg(string)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
playermode = 'player' in self.switches or lhs.startswith('*')
|
||||||
|
|
||||||
# locate the object
|
# locate the object
|
||||||
obj = caller.search(lhs, global_search=True)
|
obj = caller.search(lhs, global_search=True, player=playermode)
|
||||||
if not obj:
|
if not obj:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not rhs:
|
if not rhs:
|
||||||
|
|
||||||
if not obj.access(caller, 'examine'):
|
if not obj.access(caller, 'examine'):
|
||||||
caller.msg("You are not allowed to examine this object.")
|
caller.msg("You are not allowed to examine this object.")
|
||||||
return
|
return
|
||||||
|
|
@ -397,11 +403,9 @@ class CmdPerm(MuxCommand):
|
||||||
|
|
||||||
for perm in self.rhslist:
|
for perm in self.rhslist:
|
||||||
|
|
||||||
perm = perm.lower()
|
|
||||||
|
|
||||||
# don't allow to set a permission higher in the hierarchy than the one the
|
# don't allow to set a permission higher in the hierarchy than the one the
|
||||||
# caller has (to prevent self-escalation)
|
# caller has (to prevent self-escalation)
|
||||||
if perm in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm):
|
if perm.lower() in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm):
|
||||||
caller.msg("You cannot assign a permission higher than the one you have yourself.")
|
caller.msg("You cannot assign a permission higher than the one you have yourself.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -416,45 +420,6 @@ class CmdPerm(MuxCommand):
|
||||||
if tstring:
|
if tstring:
|
||||||
obj.msg(tstring.strip())
|
obj.msg(tstring.strip())
|
||||||
|
|
||||||
|
|
||||||
class CmdPuppet(MuxCommand):
|
|
||||||
"""
|
|
||||||
Switch control to an object
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
@puppet <character object>
|
|
||||||
|
|
||||||
This will attempt to "become" a different character. Note that this command does not check so that
|
|
||||||
the target object has the appropriate cmdset. You cannot puppet a character that is already "taken".
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = "@puppet"
|
|
||||||
locks = "cmd:perm(puppet) or perm(Builders)"
|
|
||||||
help_category = "Admin"
|
|
||||||
|
|
||||||
def func(self):
|
|
||||||
"""
|
|
||||||
Simple puppet method (does not check permissions)
|
|
||||||
"""
|
|
||||||
caller = self.caller
|
|
||||||
if not self.args:
|
|
||||||
caller.msg("Usage: @puppet <character>")
|
|
||||||
return
|
|
||||||
|
|
||||||
player = caller.player
|
|
||||||
new_character = caller.search(self.args)
|
|
||||||
if not new_character:
|
|
||||||
return
|
|
||||||
if not utils.inherits_from(new_character, settings.BASE_CHARACTER_TYPECLASS):
|
|
||||||
caller.msg("%s is not a Character." % self.args)
|
|
||||||
return
|
|
||||||
if new_character.player:
|
|
||||||
caller.msg("This character is already under the control of a player.")
|
|
||||||
if player.swap_character(new_character):
|
|
||||||
new_character.msg("You now control %s." % new_character.name)
|
|
||||||
else:
|
|
||||||
caller.msg("You cannot control %s." % new_character.name)
|
|
||||||
|
|
||||||
class CmdWall(MuxCommand):
|
class CmdWall(MuxCommand):
|
||||||
"""
|
"""
|
||||||
@wall
|
@wall
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ Building and world design commands
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from src.objects.models import ObjectDB, ObjAttribute
|
from src.objects.models import ObjectDB, ObjAttribute
|
||||||
|
from src.players.models import PlayerAttribute
|
||||||
from src.utils import create, utils, debug
|
from src.utils import create, utils, debug
|
||||||
from src.commands.default.muxcommand import MuxCommand
|
from src.commands.default.muxcommand import MuxCommand
|
||||||
|
|
||||||
|
|
@ -122,7 +123,7 @@ class CmdSetObjAlias(MuxCommand):
|
||||||
old_aliases = obj.aliases
|
old_aliases = obj.aliases
|
||||||
if old_aliases:
|
if old_aliases:
|
||||||
caller.msg("Cleared aliases from %s: %s" % (obj.key, ", ".join(old_aliases)))
|
caller.msg("Cleared aliases from %s: %s" % (obj.key, ", ".join(old_aliases)))
|
||||||
del obj.dbobj.aliases # TODO: del does not understand indirect typeclass reference!
|
del obj.dbobj.aliases
|
||||||
else:
|
else:
|
||||||
caller.msg("No aliases to clear.")
|
caller.msg("No aliases to clear.")
|
||||||
return
|
return
|
||||||
|
|
@ -1389,16 +1390,25 @@ class CmdExamine(ObjManipCommand):
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
examine [<object>[/attrname]]
|
examine [<object>[/attrname]]
|
||||||
|
examine [*<player>[/attrname]]
|
||||||
|
|
||||||
|
Switch:
|
||||||
|
player - examine a Player (same as adding *)
|
||||||
|
|
||||||
The examine command shows detailed game info about an
|
The examine command shows detailed game info about an
|
||||||
object and optionally a specific attribute on it.
|
object and optionally a specific attribute on it.
|
||||||
If object is not specified, the current location is examined.
|
If object is not specified, the current location is examined.
|
||||||
|
|
||||||
|
Append a * before the search string to examine a player.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
key = "@examine"
|
key = "@examine"
|
||||||
aliases = ["@ex","ex", "exam", "examine"]
|
aliases = ["@ex","ex", "exam", "examine"]
|
||||||
locks = "cmd:perm(examine) or perm(Builders)"
|
locks = "cmd:perm(examine) or perm(Builders)"
|
||||||
help_category = "Building"
|
help_category = "Building"
|
||||||
|
|
||||||
|
player_mode = False
|
||||||
|
|
||||||
def format_attributes(self, obj, attrname=None, crop=True):
|
def format_attributes(self, obj, attrname=None, crop=True):
|
||||||
"""
|
"""
|
||||||
Helper function that returns info about attributes and/or
|
Helper function that returns info about attributes and/or
|
||||||
|
|
@ -1410,6 +1420,9 @@ class CmdExamine(ObjManipCommand):
|
||||||
ndb_attr = [(attrname, object.__getattribute__(obj.ndb, attrname))]
|
ndb_attr = [(attrname, object.__getattribute__(obj.ndb, attrname))]
|
||||||
except Exception:
|
except Exception:
|
||||||
ndb_attr = None
|
ndb_attr = None
|
||||||
|
else:
|
||||||
|
if player_mode:
|
||||||
|
db_attr = [(attr.key, attr.value) for attr in PlayerAttribute.objects.filter(db_obj=obj)]
|
||||||
else:
|
else:
|
||||||
db_attr = [(attr.key, attr.value) for attr in ObjAttribute.objects.filter(db_obj=obj)]
|
db_attr = [(attr.key, attr.value) for attr in ObjAttribute.objects.filter(db_obj=obj)]
|
||||||
try:
|
try:
|
||||||
|
|
@ -1439,13 +1452,13 @@ class CmdExamine(ObjManipCommand):
|
||||||
returns a string.
|
returns a string.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if obj.has_player:
|
if hasattr(obj, "has_player") and obj.has_player:
|
||||||
string = "\n{wName/key{n: {c%s{n (%s)" % (obj.name, obj.dbref)
|
string = "\n{wName/key{n: {c%s{n (%s)" % (obj.name, obj.dbref)
|
||||||
else:
|
else:
|
||||||
string = "\n{wName/key{n: {C%s{n (%s)" % (obj.name, obj.dbref)
|
string = "\n{wName/key{n: {C%s{n (%s)" % (obj.name, obj.dbref)
|
||||||
if obj.aliases:
|
if hasattr(obj, "aliases") and obj.aliases:
|
||||||
string += "\n{wAliases{n: %s" % (", ".join(obj.aliases))
|
string += "\n{wAliases{n: %s" % (", ".join(obj.aliases))
|
||||||
if obj.has_player:
|
if hasattr(obj, "has_player") and obj.has_player:
|
||||||
string += "\n{wPlayer{n: {c%s{n" % obj.player.name
|
string += "\n{wPlayer{n: {c%s{n" % obj.player.name
|
||||||
perms = obj.player.permissions
|
perms = obj.player.permissions
|
||||||
if obj.player.is_superuser:
|
if obj.player.is_superuser:
|
||||||
|
|
@ -1453,10 +1466,11 @@ class CmdExamine(ObjManipCommand):
|
||||||
elif not perms:
|
elif not perms:
|
||||||
perms = ["<None>"]
|
perms = ["<None>"]
|
||||||
string += "\n{wPlayer Perms{n: %s" % (", ".join(perms))
|
string += "\n{wPlayer Perms{n: %s" % (", ".join(perms))
|
||||||
|
|
||||||
string += "\n{wTypeclass{n: %s (%s)" % (obj.typeclass, obj.typeclass_path)
|
string += "\n{wTypeclass{n: %s (%s)" % (obj.typeclass, obj.typeclass_path)
|
||||||
|
|
||||||
|
if hasattr(obj, "location"):
|
||||||
string += "\n{wLocation{n: %s" % obj.location
|
string += "\n{wLocation{n: %s" % obj.location
|
||||||
if obj.destination:
|
if hasattr(obj, "destination") and obj.destination:
|
||||||
string += "\n{wDestination{n: %s" % obj.destination
|
string += "\n{wDestination{n: %s" % obj.destination
|
||||||
perms = obj.permissions
|
perms = obj.permissions
|
||||||
if perms:
|
if perms:
|
||||||
|
|
@ -1467,8 +1481,8 @@ class CmdExamine(ObjManipCommand):
|
||||||
|
|
||||||
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
|
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
|
||||||
cmdsetstr = "\n".join([utils.fill(cmdset, indent=2) for cmdset in str(obj.cmdset).split("\n")])
|
cmdsetstr = "\n".join([utils.fill(cmdset, indent=2) for cmdset in str(obj.cmdset).split("\n")])
|
||||||
string += "\n{wCurrent Cmdset (before permission checks){n:\n %s" % cmdsetstr
|
string += "\n{wCurrent Cmdset (including permission checks){n:\n %s" % cmdsetstr
|
||||||
if obj.scripts.all():
|
if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all():
|
||||||
string += "\n{wScripts{n:\n %s" % obj.scripts
|
string += "\n{wScripts{n:\n %s" % obj.scripts
|
||||||
# add the attributes
|
# add the attributes
|
||||||
string += self.format_attributes(obj)
|
string += self.format_attributes(obj)
|
||||||
|
|
@ -1476,9 +1490,9 @@ class CmdExamine(ObjManipCommand):
|
||||||
exits = []
|
exits = []
|
||||||
pobjs = []
|
pobjs = []
|
||||||
things = []
|
things = []
|
||||||
|
if hasattr(obj, "contents"):
|
||||||
for content in obj.contents:
|
for content in obj.contents:
|
||||||
if content.destination:
|
if content.destination:
|
||||||
# an exit
|
|
||||||
exits.append(content)
|
exits.append(content)
|
||||||
elif content.player:
|
elif content.player:
|
||||||
pobjs.append(content)
|
pobjs.append(content)
|
||||||
|
|
@ -1506,18 +1520,20 @@ class CmdExamine(ObjManipCommand):
|
||||||
caller.execute_cmd('look %s' % obj.name)
|
caller.execute_cmd('look %s' % obj.name)
|
||||||
return
|
return
|
||||||
string = self.format_output(obj)
|
string = self.format_output(obj)
|
||||||
|
caller.msg(string.strip())
|
||||||
|
return
|
||||||
|
|
||||||
else:
|
|
||||||
# we have given a specific target object
|
# we have given a specific target object
|
||||||
|
|
||||||
string = ""
|
string = ""
|
||||||
|
|
||||||
for objdef in self.lhs_objattr:
|
for objdef in self.lhs_objattr:
|
||||||
|
|
||||||
obj_name = objdef['name']
|
obj_name = objdef['name']
|
||||||
obj_attrs = objdef['attrs']
|
obj_attrs = objdef['attrs']
|
||||||
|
|
||||||
obj = caller.search(obj_name)
|
global player_mode
|
||||||
|
player_mode = "player" in self.switches or obj_name.startswith('*')
|
||||||
|
|
||||||
|
obj = caller.search(obj_name, player=player_mode)
|
||||||
if not obj:
|
if not obj:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -1532,9 +1548,6 @@ class CmdExamine(ObjManipCommand):
|
||||||
string += self.format_attributes(obj, attrname, crop=False)
|
string += self.format_attributes(obj, attrname, crop=False)
|
||||||
else:
|
else:
|
||||||
string += self.format_output(obj)
|
string += self.format_output(obj)
|
||||||
string = string.strip()
|
|
||||||
# Send it all
|
|
||||||
if string:
|
|
||||||
caller.msg(string.strip())
|
caller.msg(string.strip())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,14 @@ class DefaultCmdSet(CmdSet):
|
||||||
# The general commands
|
# The general commands
|
||||||
self.add(general.CmdLook())
|
self.add(general.CmdLook())
|
||||||
self.add(general.CmdHome())
|
self.add(general.CmdHome())
|
||||||
self.add(general.CmdPassword())
|
self.add(general.CmdWho())
|
||||||
self.add(general.CmdInventory())
|
self.add(general.CmdInventory())
|
||||||
self.add(general.CmdQuit())
|
|
||||||
self.add(general.CmdPose())
|
self.add(general.CmdPose())
|
||||||
self.add(general.CmdNick())
|
self.add(general.CmdNick())
|
||||||
self.add(general.CmdGet())
|
self.add(general.CmdGet())
|
||||||
self.add(general.CmdDrop())
|
self.add(general.CmdDrop())
|
||||||
self.add(general.CmdWho())
|
|
||||||
self.add(general.CmdSay())
|
self.add(general.CmdSay())
|
||||||
self.add(general.CmdAccess())
|
self.add(general.CmdAccess())
|
||||||
self.add(general.CmdEncoding())
|
|
||||||
|
|
||||||
# The help system
|
# The help system
|
||||||
self.add(help.CmdHelp())
|
self.add(help.CmdHelp())
|
||||||
|
|
@ -52,7 +49,6 @@ class DefaultCmdSet(CmdSet):
|
||||||
self.add(admin.CmdEmit())
|
self.add(admin.CmdEmit())
|
||||||
self.add(admin.CmdNewPassword())
|
self.add(admin.CmdNewPassword())
|
||||||
self.add(admin.CmdPerm())
|
self.add(admin.CmdPerm())
|
||||||
self.add(admin.CmdPuppet())
|
|
||||||
self.add(admin.CmdWall())
|
self.add(admin.CmdWall())
|
||||||
|
|
||||||
# Building and world manipulation
|
# Building and world manipulation
|
||||||
|
|
@ -80,24 +76,6 @@ class DefaultCmdSet(CmdSet):
|
||||||
self.add(building.CmdScript())
|
self.add(building.CmdScript())
|
||||||
self.add(building.CmdHome())
|
self.add(building.CmdHome())
|
||||||
|
|
||||||
# Comm commands
|
|
||||||
self.add(comms.CmdAddCom())
|
|
||||||
self.add(comms.CmdDelCom())
|
|
||||||
self.add(comms.CmdAllCom())
|
|
||||||
self.add(comms.CmdChannels())
|
|
||||||
self.add(comms.CmdCdestroy())
|
|
||||||
self.add(comms.CmdChannelCreate())
|
|
||||||
self.add(comms.CmdCset())
|
|
||||||
self.add(comms.CmdCBoot())
|
|
||||||
self.add(comms.CmdCemit())
|
|
||||||
self.add(comms.CmdCWho())
|
|
||||||
self.add(comms.CmdCdesc())
|
|
||||||
self.add(comms.CmdPage())
|
|
||||||
self.add(comms.CmdIRC2Chan())
|
|
||||||
self.add(comms.CmdIMC2Chan())
|
|
||||||
self.add(comms.CmdIMCInfo())
|
|
||||||
self.add(comms.CmdIMCTell())
|
|
||||||
|
|
||||||
# Batchprocessor commands
|
# Batchprocessor commands
|
||||||
self.add(batchprocess.CmdBatchCommands())
|
self.add(batchprocess.CmdBatchCommands())
|
||||||
self.add(batchprocess.CmdBatchCode())
|
self.add(batchprocess.CmdBatchCode())
|
||||||
|
|
|
||||||
55
src/commands/default/cmdset_ooc.py
Normal file
55
src/commands/default/cmdset_ooc.py
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
"""
|
||||||
|
|
||||||
|
This is the cmdset for OutOfCharacter (OOC) commands.
|
||||||
|
These are stored on the Player object and should
|
||||||
|
thus be able to handle getting a Player object
|
||||||
|
as caller rather than a Character.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from src.commands.cmdset import CmdSet
|
||||||
|
from src.commands.default import help, comms, general, admin
|
||||||
|
|
||||||
|
class OOCCmdSet(CmdSet):
|
||||||
|
"""
|
||||||
|
Implements the player command set.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = "DefaultOOC"
|
||||||
|
priority = -5
|
||||||
|
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
"Populates the cmdset"
|
||||||
|
|
||||||
|
# general commands
|
||||||
|
self.add(general.CmdOOCLook())
|
||||||
|
self.add(general.CmdIC())
|
||||||
|
self.add(general.CmdOOC())
|
||||||
|
self.add(general.CmdEncoding())
|
||||||
|
self.add(general.CmdQuit())
|
||||||
|
self.add(general.CmdPassword())
|
||||||
|
|
||||||
|
# help command
|
||||||
|
self.add(help.CmdHelp())
|
||||||
|
|
||||||
|
# admin commands
|
||||||
|
self.add(admin.CmdBoot())
|
||||||
|
self.add(admin.CmdDelPlayer())
|
||||||
|
self.add(admin.CmdNewPassword())
|
||||||
|
|
||||||
|
# Comm commands
|
||||||
|
self.add(comms.CmdAddCom())
|
||||||
|
self.add(comms.CmdDelCom())
|
||||||
|
self.add(comms.CmdAllCom())
|
||||||
|
self.add(comms.CmdChannels())
|
||||||
|
self.add(comms.CmdCdestroy())
|
||||||
|
self.add(comms.CmdChannelCreate())
|
||||||
|
self.add(comms.CmdCset())
|
||||||
|
self.add(comms.CmdCBoot())
|
||||||
|
self.add(comms.CmdCemit())
|
||||||
|
self.add(comms.CmdCWho())
|
||||||
|
self.add(comms.CmdCdesc())
|
||||||
|
self.add(comms.CmdPage())
|
||||||
|
self.add(comms.CmdIRC2Chan())
|
||||||
|
self.add(comms.CmdIMC2Chan())
|
||||||
|
self.add(comms.CmdIMCInfo())
|
||||||
|
self.add(comms.CmdIMCTell())
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
"""
|
"""
|
||||||
Comsys command module.
|
Comsystem command module.
|
||||||
|
|
||||||
|
Comm commands are OOC commands and intended to be made available to
|
||||||
|
the Player at all times (they go into the PlayerCmdSet). So we
|
||||||
|
make sure to homogenize self.caller to always be the player object
|
||||||
|
for easy handling.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection
|
from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection
|
||||||
|
|
@ -30,6 +36,25 @@ def find_channel(caller, channelname, silent=False, noaliases=False):
|
||||||
return None
|
return None
|
||||||
return channels[0]
|
return channels[0]
|
||||||
|
|
||||||
|
class CommCommand(MuxCommand):
|
||||||
|
"""
|
||||||
|
This is a parent for comm-commands. Since
|
||||||
|
These commands are to be available to the
|
||||||
|
Player, we make sure to homogenize the caller
|
||||||
|
here, so it's always seen as a player to the
|
||||||
|
command body.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
"overload parts of parse"
|
||||||
|
|
||||||
|
# run parent
|
||||||
|
super(CommCommand, self).parse()
|
||||||
|
# fix obj->player
|
||||||
|
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
|
||||||
|
# an object. Convert it to its player.
|
||||||
|
self.caller = self.caller.player
|
||||||
|
|
||||||
class CmdAddCom(MuxCommand):
|
class CmdAddCom(MuxCommand):
|
||||||
"""
|
"""
|
||||||
addcom - subscribe to a channel with optional alias
|
addcom - subscribe to a channel with optional alias
|
||||||
|
|
@ -46,14 +71,14 @@ class CmdAddCom(MuxCommand):
|
||||||
key = "addcom"
|
key = "addcom"
|
||||||
aliases = ["aliaschan","chanalias"]
|
aliases = ["aliaschan","chanalias"]
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
locks = "cmd:not perm(channel_banned)"
|
locks = "cmd:not pperm(channel_banned)"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"Implement the command"
|
"Implement the command"
|
||||||
|
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
args = self.args
|
args = self.args
|
||||||
player = caller.player
|
player = caller
|
||||||
|
|
||||||
if not args:
|
if not args:
|
||||||
caller.msg("Usage: addcom [alias =] channelname.")
|
caller.msg("Usage: addcom [alias =] channelname.")
|
||||||
|
|
@ -120,7 +145,7 @@ class CmdDelCom(MuxCommand):
|
||||||
"Implementing the command. "
|
"Implementing the command. "
|
||||||
|
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
player = caller.player
|
player = caller
|
||||||
|
|
||||||
if not self.args:
|
if not self.args:
|
||||||
caller.msg("Usage: delcom <alias or channel>")
|
caller.msg("Usage: delcom <alias or channel>")
|
||||||
|
|
@ -169,7 +194,7 @@ class CmdAllCom(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "allcom"
|
key = "allcom"
|
||||||
locks = "cmd: not perm(channel_banned)"
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -189,7 +214,7 @@ class CmdAllCom(MuxCommand):
|
||||||
caller.execute_cmd("addcom %s" % channel.key)
|
caller.execute_cmd("addcom %s" % channel.key)
|
||||||
elif args == "off":
|
elif args == "off":
|
||||||
#get names all subscribed channels and disconnect from them all
|
#get names all subscribed channels and disconnect from them all
|
||||||
channels = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller.player)]
|
channels = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller)]
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
caller.execute_cmd("delcom %s" % channel.key)
|
caller.execute_cmd("delcom %s" % channel.key)
|
||||||
elif args == "destroy":
|
elif args == "destroy":
|
||||||
|
|
@ -230,7 +255,7 @@ class CmdChannels(MuxCommand):
|
||||||
key = "@channels"
|
key = "@channels"
|
||||||
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
|
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
locks = "cmd: not perm(channel_banned)"
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"Implement function"
|
"Implement function"
|
||||||
|
|
@ -243,7 +268,7 @@ class CmdChannels(MuxCommand):
|
||||||
caller.msg("No channels available.")
|
caller.msg("No channels available.")
|
||||||
return
|
return
|
||||||
# all channel we are already subscribed to
|
# all channel we are already subscribed to
|
||||||
subs = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller.player)]
|
subs = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller)]
|
||||||
|
|
||||||
if self.cmdstring != "comlist":
|
if self.cmdstring != "comlist":
|
||||||
|
|
||||||
|
|
@ -298,7 +323,7 @@ class CmdCdestroy(MuxCommand):
|
||||||
|
|
||||||
key = "@cdestroy"
|
key = "@cdestroy"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
locks = "cmd: not perm(channel_banned)"
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"Destroy objects cleanly."
|
"Destroy objects cleanly."
|
||||||
|
|
@ -337,7 +362,7 @@ class CmdCBoot(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "@cboot"
|
key = "@cboot"
|
||||||
locks = "cmd: not perm(channel_banned)"
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -352,12 +377,12 @@ class CmdCBoot(MuxCommand):
|
||||||
if not channel:
|
if not channel:
|
||||||
return
|
return
|
||||||
reason = ""
|
reason = ""
|
||||||
player = None
|
|
||||||
if ":" in self.rhs:
|
if ":" in self.rhs:
|
||||||
playername, reason = self.rhs.rsplit(":", 1)
|
playername, reason = self.rhs.rsplit(":", 1)
|
||||||
player = self.caller.search("*%s" % playername.lstrip('*'))
|
searchstring = playername.lstrip('*')
|
||||||
if not player:
|
else:
|
||||||
player = self.caller.search("*%s" % self.rhs.lstrip('*'))
|
searchstring = self.rhs.lstrip('*')
|
||||||
|
player = self.caller.search(searchstring, player=True)
|
||||||
if not player:
|
if not player:
|
||||||
return
|
return
|
||||||
if reason:
|
if reason:
|
||||||
|
|
@ -400,7 +425,7 @@ class CmdCemit(MuxCommand):
|
||||||
|
|
||||||
key = "@cemit"
|
key = "@cemit"
|
||||||
aliases = ["@cmsg"]
|
aliases = ["@cmsg"]
|
||||||
locks = "cmd: not perm(channel_banned)"
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -437,7 +462,7 @@ class CmdCWho(MuxCommand):
|
||||||
List who is connected to a given channel you have access to.
|
List who is connected to a given channel you have access to.
|
||||||
"""
|
"""
|
||||||
key = "@cwho"
|
key = "@cwho"
|
||||||
locks = "cmd: not perm(channel_banned)"
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -475,7 +500,7 @@ class CmdChannelCreate(MuxCommand):
|
||||||
|
|
||||||
key = "@ccreate"
|
key = "@ccreate"
|
||||||
aliases = "channelcreate"
|
aliases = "channelcreate"
|
||||||
locks = "cmd:not perm(channel_banned)"
|
locks = "cmd:not pperm(channel_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -522,7 +547,7 @@ class CmdCset(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "@cset"
|
key = "@cset"
|
||||||
locks = "cmd:not perm(channel_banned)"
|
locks = "cmd:not pperm(channel_banned)"
|
||||||
aliases = ["@cclock"]
|
aliases = ["@cclock"]
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
|
|
@ -568,7 +593,7 @@ class CmdCdesc(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "@cdesc"
|
key = "@cdesc"
|
||||||
locks = "cmd:not perm(channel_banned)"
|
locks = "cmd:not pperm(channel_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -611,7 +636,7 @@ class CmdPage(MuxCommand):
|
||||||
|
|
||||||
key = "page"
|
key = "page"
|
||||||
aliases = ['tell']
|
aliases = ['tell']
|
||||||
locks = "cmd:not perm(page_banned)"
|
locks = "cmd:not pperm(page_banned)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -619,7 +644,7 @@ class CmdPage(MuxCommand):
|
||||||
"Implement function using the Msg methods"
|
"Implement function using the Msg methods"
|
||||||
|
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
player = caller.player
|
player = caller
|
||||||
|
|
||||||
# get the messages we've sent
|
# get the messages we've sent
|
||||||
messages_we_sent = list(Msg.objects.get_messages_by_sender(player))
|
messages_we_sent = list(Msg.objects.get_messages_by_sender(player))
|
||||||
|
|
@ -751,7 +776,7 @@ class CmdIRC2Chan(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "@irc2chan"
|
key = "@irc2chan"
|
||||||
locks = "cmd:serversetting(IRC_ENABLED) and perm(Immortals)"
|
locks = "cmd:serversetting(IRC_ENABLED) and pperm(Immortals)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -840,7 +865,7 @@ class CmdIMC2Chan(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "@imc2chan"
|
key = "@imc2chan"
|
||||||
locks = "cmd:serversetting(IMC2_ENABLED) and perm(Immortals)"
|
locks = "cmd:serversetting(IMC2_ENABLED) and pperm(Immortals)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -923,7 +948,7 @@ class CmdIMCInfo(MuxCommand):
|
||||||
|
|
||||||
key = "@imcinfo"
|
key = "@imcinfo"
|
||||||
aliases = ["@imcchanlist", "@imclist", "@imcwhois"]
|
aliases = ["@imcchanlist", "@imclist", "@imcwhois"]
|
||||||
locks = "cmd: serversetting(IMC2_ENABLED) and perm(Wizards)"
|
locks = "cmd: serversetting(IMC2_ENABLED) and pperm(Wizards)"
|
||||||
help_category = "Comms"
|
help_category = "Comms"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -982,7 +1007,7 @@ class CmdIMCInfo(MuxCommand):
|
||||||
return
|
return
|
||||||
from src.comms.imc2 import IMC2_CLIENT
|
from src.comms.imc2 import IMC2_CLIENT
|
||||||
self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.")
|
self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.")
|
||||||
IMC2_CLIENT.msg_imc2(None, from_obj=self.caller.player, packet_type="imcwhois", data={"target":self.args})
|
IMC2_CLIENT.msg_imc2(None, from_obj=self.caller, packet_type="imcwhois", data={"target":self.args})
|
||||||
|
|
||||||
elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist":
|
elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist":
|
||||||
# show channels
|
# show channels
|
||||||
|
|
@ -1051,6 +1076,6 @@ class CmdIMCTell(MuxCommand):
|
||||||
data = {"target":target, "destination":destination}
|
data = {"target":target, "destination":destination}
|
||||||
|
|
||||||
# send to imc2
|
# send to imc2
|
||||||
IMC2_CLIENT.msg_imc2(message, from_obj=self.caller.player, packet_type="imctell", data=data)
|
IMC2_CLIENT.msg_imc2(message, from_obj=self.caller, packet_type="imctell", data=data)
|
||||||
|
|
||||||
self.caller.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message))
|
self.caller.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message))
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ now.
|
||||||
import time
|
import time
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from src.server.sessionhandler import SESSIONS
|
from src.server.sessionhandler import SESSIONS
|
||||||
from src.objects.models import HANDLE_SEARCH_ERRORS
|
|
||||||
from src.utils import utils
|
from src.utils import utils
|
||||||
from src.objects.models import Nick
|
from src.objects.models import ObjectNick as Nick
|
||||||
from src.commands.default.muxcommand import MuxCommand
|
from src.commands.default.muxcommand import MuxCommand
|
||||||
|
|
||||||
|
AT_SEARCH_RESULT = utils.mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||||
|
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS
|
||||||
|
|
||||||
class CmdHome(MuxCommand):
|
class CmdHome(MuxCommand):
|
||||||
"""
|
"""
|
||||||
home
|
home
|
||||||
|
|
@ -45,7 +47,7 @@ class CmdLook(MuxCommand):
|
||||||
Observes your location or objects in your vicinity.
|
Observes your location or objects in your vicinity.
|
||||||
"""
|
"""
|
||||||
key = "look"
|
key = "look"
|
||||||
aliases = ["l"]
|
aliases = ["l", "ls"]
|
||||||
locks = "cmd:all()"
|
locks = "cmd:all()"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
|
|
@ -53,7 +55,7 @@ class CmdLook(MuxCommand):
|
||||||
Handle the looking.
|
Handle the looking.
|
||||||
"""
|
"""
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
args = self.args # caller.msg(inp)
|
args = self.args
|
||||||
|
|
||||||
if args:
|
if args:
|
||||||
# Use search to handle duplicate/nonexistant results.
|
# Use search to handle duplicate/nonexistant results.
|
||||||
|
|
@ -63,8 +65,9 @@ class CmdLook(MuxCommand):
|
||||||
else:
|
else:
|
||||||
looking_at_obj = caller.location
|
looking_at_obj = caller.location
|
||||||
if not looking_at_obj:
|
if not looking_at_obj:
|
||||||
caller.msg("Location: None")
|
caller.msg("You have no location to look at!")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not hasattr(looking_at_obj, 'return_appearance'):
|
if not hasattr(looking_at_obj, 'return_appearance'):
|
||||||
# this is likely due to us having a player instead
|
# this is likely due to us having a player instead
|
||||||
looking_at_obj = looking_at_obj.character
|
looking_at_obj = looking_at_obj.character
|
||||||
|
|
@ -89,6 +92,8 @@ class CmdPassword(MuxCommand):
|
||||||
"hook function."
|
"hook function."
|
||||||
|
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
|
if hasattr(caller, "player"):
|
||||||
|
caller = caller.player
|
||||||
|
|
||||||
if not self.rhs:
|
if not self.rhs:
|
||||||
caller.msg("Usage: @password <oldpass> = <newpass>")
|
caller.msg("Usage: @password <oldpass> = <newpass>")
|
||||||
|
|
@ -96,7 +101,7 @@ class CmdPassword(MuxCommand):
|
||||||
oldpass = self.lhslist[0] # this is already stripped by parse()
|
oldpass = self.lhslist[0] # this is already stripped by parse()
|
||||||
newpass = self.rhslist[0] # ''
|
newpass = self.rhslist[0] # ''
|
||||||
try:
|
try:
|
||||||
uaccount = caller.player.user
|
uaccount = caller.user
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
caller.msg("This is only applicable for players.")
|
caller.msg("This is only applicable for players.")
|
||||||
return
|
return
|
||||||
|
|
@ -309,7 +314,7 @@ class CmdDrop(MuxCommand):
|
||||||
# those in our inventory.
|
# those in our inventory.
|
||||||
results = [obj for obj in results if obj in caller.contents]
|
results = [obj for obj in results if obj in caller.contents]
|
||||||
# now we send it into the handler.
|
# now we send it into the handler.
|
||||||
obj = HANDLE_SEARCH_ERRORS(caller, self.args, results, False)
|
obj = AT_SEARCH_RESULT(caller, self.args, results, False)
|
||||||
if not obj:
|
if not obj:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -348,13 +353,13 @@ class CmdWho(MuxCommand):
|
||||||
who
|
who
|
||||||
doing
|
doing
|
||||||
|
|
||||||
Shows who is currently online. Doing is an
|
Shows who is currently online. Doing is an alias that limits info
|
||||||
alias that limits info also for those with
|
also for those with all permissions.
|
||||||
all permissions.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "who"
|
key = "who"
|
||||||
aliases = "doing"
|
aliases = "doing"
|
||||||
|
locks = "cmd:all()"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -518,17 +523,20 @@ class CmdEncoding(MuxCommand):
|
||||||
Sets the encoding.
|
Sets the encoding.
|
||||||
"""
|
"""
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
|
if hasattr(caller, 'player'):
|
||||||
|
caller = caller.player
|
||||||
|
|
||||||
if 'clear' in self.switches:
|
if 'clear' in self.switches:
|
||||||
# remove customization
|
# remove customization
|
||||||
old_encoding = caller.player.db.encoding
|
old_encoding = caller.db.encoding
|
||||||
if old_encoding:
|
if old_encoding:
|
||||||
string = "Your custom text encoding ('%s') was cleared." % old_encoding
|
string = "Your custom text encoding ('%s') was cleared." % old_encoding
|
||||||
else:
|
else:
|
||||||
string = "No custom encoding was set."
|
string = "No custom encoding was set."
|
||||||
del caller.player.db.encoding
|
del caller.db.encoding
|
||||||
elif not self.args:
|
elif not self.args:
|
||||||
# just list the encodings supported
|
# just list the encodings supported
|
||||||
pencoding = caller.player.db.encoding
|
pencoding = caller.db.encoding
|
||||||
string = ""
|
string = ""
|
||||||
if pencoding:
|
if pencoding:
|
||||||
string += "Default encoding: {g%s{n (change with {w@encoding <encoding>{n)" % pencoding
|
string += "Default encoding: {g%s{n (change with {w@encoding <encoding>{n)" % pencoding
|
||||||
|
|
@ -539,9 +547,9 @@ class CmdEncoding(MuxCommand):
|
||||||
string = "No encodings found."
|
string = "No encodings found."
|
||||||
else:
|
else:
|
||||||
# change encoding
|
# change encoding
|
||||||
old_encoding = caller.player.db.encoding
|
old_encoding = caller.db.encoding
|
||||||
encoding = self.args
|
encoding = self.args
|
||||||
caller.player.db.encoding = encoding
|
caller.db.encoding = encoding
|
||||||
string = "Your custom text encoding was changed from '%s' to '%s'." % (old_encoding, encoding)
|
string = "Your custom text encoding was changed from '%s' to '%s'." % (old_encoding, encoding)
|
||||||
caller.msg(string.strip())
|
caller.msg(string.strip())
|
||||||
|
|
||||||
|
|
@ -579,3 +587,141 @@ class CmdAccess(MuxCommand):
|
||||||
if hasattr(caller, 'player'):
|
if hasattr(caller, 'player'):
|
||||||
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
|
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
|
||||||
caller.msg(string)
|
caller.msg(string)
|
||||||
|
|
||||||
|
# OOC commands
|
||||||
|
|
||||||
|
class CmdOOCLook(CmdLook):
|
||||||
|
"""
|
||||||
|
ooc look
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
look
|
||||||
|
|
||||||
|
This is an OOC version of the look command. Since a
|
||||||
|
Player doesn't have an in-game existence, there is no
|
||||||
|
concept of location or "self". If we are controlling
|
||||||
|
a character, pass control over to normal look.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = "look"
|
||||||
|
aliases = ["l", "ls"]
|
||||||
|
locks = "cmd:all()"
|
||||||
|
help_cateogory = "General"
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
"implement the command"
|
||||||
|
|
||||||
|
self.character = None
|
||||||
|
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
|
||||||
|
# An object of some type is calling. Convert to player.
|
||||||
|
self.character = self.caller
|
||||||
|
self.caller = self.caller.player
|
||||||
|
|
||||||
|
if not self.character:
|
||||||
|
string = "You are out-of-character (OOC). "
|
||||||
|
string += "Use {w@ic{n to get back to the game, {whelp{n for more info."
|
||||||
|
self.caller.msg(string)
|
||||||
|
else:
|
||||||
|
self.caller = self.character # we have to put this back for normal look to work.
|
||||||
|
super(CmdLook, self).func()
|
||||||
|
|
||||||
|
class CmdIC(MuxCommand):
|
||||||
|
"""
|
||||||
|
Switch control to an object
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@ic <character>
|
||||||
|
|
||||||
|
Go in-character (IC) as a given Character.
|
||||||
|
|
||||||
|
This will attempt to "become" a different object assuming you have
|
||||||
|
the right to do so. You cannot become an object that is already
|
||||||
|
controlled by another player. In principle <character> can be
|
||||||
|
any in-game object as long as you have access right to puppet it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = "@ic"
|
||||||
|
locks = "cmd:all()" # must be all() or different puppeted objects won't be able to access it.
|
||||||
|
aliases = "@puppet"
|
||||||
|
help_category = "General"
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
"""
|
||||||
|
Simple puppet method
|
||||||
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
if utils.inherits_from(caller, "src.objects.objects.Object"):
|
||||||
|
caller = caller.player
|
||||||
|
|
||||||
|
new_character = None
|
||||||
|
if not self.args:
|
||||||
|
new_character = caller.db.last_puppet
|
||||||
|
if not new_character:
|
||||||
|
caller.msg("Usage: @ic <character>")
|
||||||
|
return
|
||||||
|
if not new_character:
|
||||||
|
# search for a matching character
|
||||||
|
new_character = caller.search(self.args)
|
||||||
|
if not new_character:
|
||||||
|
# the search method handles error messages etc.
|
||||||
|
return
|
||||||
|
if new_character.player:
|
||||||
|
if new_character.player == caller:
|
||||||
|
caller.msg("{RYou already are {c%s{n." % new_character.name)
|
||||||
|
else:
|
||||||
|
caller.msg("{c%s{r is already acted by another player.{n" % new_character.name)
|
||||||
|
return
|
||||||
|
if not new_character.access(caller, "puppet"):
|
||||||
|
caller.msg("{rYou may not become %s.{n" % new_character.name)
|
||||||
|
return
|
||||||
|
old_char = None
|
||||||
|
if caller.character:
|
||||||
|
# save the old character. We only assign this to last_puppet if swap is successful.
|
||||||
|
old_char = caller.character
|
||||||
|
if caller.swap_character(new_character):
|
||||||
|
new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name)
|
||||||
|
caller.db.last_puppet = old_char
|
||||||
|
new_character.execute_cmd("look")
|
||||||
|
else:
|
||||||
|
caller.msg("{rYou cannot become {C%s{n." % new_character.name)
|
||||||
|
|
||||||
|
class CmdOOC(MuxCommand):
|
||||||
|
"""
|
||||||
|
@ooc - go ooc
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@ooc
|
||||||
|
|
||||||
|
Go out-of-character (OOC).
|
||||||
|
|
||||||
|
This will leave your current character and put you in a incorporeal OOC state.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = "@ooc"
|
||||||
|
locks = "cmd:all()" # this must be all(), or different puppeted objects won't be able to access it.
|
||||||
|
aliases = "@unpuppet"
|
||||||
|
help_category = "General"
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
"Implement function"
|
||||||
|
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
|
if utils.inherits_from(caller, "src.objects.objects.Object"):
|
||||||
|
caller = self.caller.player
|
||||||
|
|
||||||
|
if not caller.character:
|
||||||
|
string = "You are already OOC."
|
||||||
|
caller.msg(string)
|
||||||
|
return
|
||||||
|
|
||||||
|
caller.db.last_puppet = caller.character
|
||||||
|
|
||||||
|
# disconnect
|
||||||
|
caller.character.player = None
|
||||||
|
caller.character = None
|
||||||
|
|
||||||
|
|
||||||
|
caller.msg("\n{GYou go OOC.{n\n")
|
||||||
|
caller.execute_cmd("look")
|
||||||
|
|
|
||||||
|
|
@ -441,5 +441,12 @@ class TestCwho(CommandTest):
|
||||||
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
|
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
|
||||||
self.execute_cmd("@cwho testchan1b", "Channel subscriptions")
|
self.execute_cmd("@cwho testchan1b", "Channel subscriptions")
|
||||||
|
|
||||||
|
# OOC commands
|
||||||
|
|
||||||
|
#class TestOOC_and_IC(CommandTest): # can't be tested it seems, causes errors in other commands (?)
|
||||||
|
# def test_call(self):
|
||||||
|
# self.execute_cmd("@ooc", "\nYou go OOC.")
|
||||||
|
# self.execute_cmd("@ic", "\nYou become TestChar")
|
||||||
|
|
||||||
# Unloggedin commands
|
# Unloggedin commands
|
||||||
# these cannot be tested from here.
|
# these cannot be tested from here.
|
||||||
|
|
|
||||||
|
|
@ -62,49 +62,81 @@ class CmdConnect(MuxCommand):
|
||||||
|
|
||||||
# We are logging in, get/setup the player object controlled by player
|
# We are logging in, get/setup the player object controlled by player
|
||||||
|
|
||||||
character = player.character
|
|
||||||
if not character:
|
|
||||||
# Create a new character object to tie the player to. This should
|
|
||||||
# usually not be needed unless the old character object was manually
|
|
||||||
# deleted.
|
|
||||||
default_home_id = ServerConfig.objects.conf("default_home")
|
|
||||||
default_home = ObjectDB.objects.get_id(default_home_id)
|
|
||||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
|
||||||
character = create.create_object(typeclass=typeclass,
|
|
||||||
key=player.name,
|
|
||||||
location=default_home,
|
|
||||||
home=default_home,
|
|
||||||
player=player)
|
|
||||||
|
|
||||||
character.db.FIRST_LOGIN = "True"
|
|
||||||
|
|
||||||
# Getting ready to log the player in.
|
|
||||||
|
|
||||||
# Check if this is the first time the
|
# Check if this is the first time the
|
||||||
# *player* connects
|
# *player* connects
|
||||||
if player.db.FIRST_LOGIN:
|
if player.db.FIRST_LOGIN:
|
||||||
player.at_first_login()
|
player.at_first_login()
|
||||||
del player.db.FIRST_LOGIN
|
del player.db.FIRST_LOGIN
|
||||||
|
player.at_pre_login()
|
||||||
|
|
||||||
# check if this is the first time the *character*
|
character = player.character
|
||||||
# character (needs not be the first time the player
|
if character:
|
||||||
# does so, e.g. if the player has several characters)
|
# this player has a character. Check if it's the
|
||||||
|
# first time *this character* logs in
|
||||||
if character.db.FIRST_LOGIN:
|
if character.db.FIRST_LOGIN:
|
||||||
character.at_first_login()
|
character.at_first_login()
|
||||||
del character.db.FIRST_LOGIN
|
del character.db.FIRST_LOGIN
|
||||||
|
# run character login hook
|
||||||
# actually do the login, calling
|
|
||||||
# customization hooks before and after.
|
|
||||||
player.at_pre_login()
|
|
||||||
character.at_pre_login()
|
character.at_pre_login()
|
||||||
|
|
||||||
|
# actually do the login
|
||||||
session.session_login(player)
|
session.session_login(player)
|
||||||
|
|
||||||
|
# post-login hooks
|
||||||
player.at_post_login()
|
player.at_post_login()
|
||||||
|
if character:
|
||||||
character.at_post_login()
|
character.at_post_login()
|
||||||
|
character.execute_cmd('look')
|
||||||
|
else:
|
||||||
|
player.execute_cmd('look')
|
||||||
|
|
||||||
# run look
|
# run look
|
||||||
#print "character:", character, character.scripts.all(), character.cmdset.current
|
#print "character:", character, character.scripts.all(), character.cmdset.current
|
||||||
character.execute_cmd('look')
|
|
||||||
|
#
|
||||||
|
# character = player.character
|
||||||
|
# if not character:
|
||||||
|
# # Create a new character object to tie the player to. This should
|
||||||
|
# # usually not be needed unless the old character object was manually
|
||||||
|
# # deleted.
|
||||||
|
# default_home_id = ServerConfig.objects.conf("default_home")
|
||||||
|
# default_home = ObjectDB.objects.get_id(default_home_id)
|
||||||
|
# typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||||
|
# character = create.create_object(typeclass=typeclass,
|
||||||
|
# key=player.name,
|
||||||
|
# location=default_home,
|
||||||
|
# home=default_home,
|
||||||
|
# player=player)
|
||||||
|
|
||||||
|
# character.db.FIRST_LOGIN = "True"
|
||||||
|
|
||||||
|
# # Getting ready to log the player in.
|
||||||
|
|
||||||
|
# # Check if this is the first time the
|
||||||
|
# # *player* connects
|
||||||
|
# if player.db.FIRST_LOGIN:
|
||||||
|
# player.at_first_login()
|
||||||
|
# del player.db.FIRST_LOGIN
|
||||||
|
|
||||||
|
# # check if this is the first time the *character*
|
||||||
|
# # character (needs not be the first time the player
|
||||||
|
# # does so, e.g. if the player has several characters)
|
||||||
|
# if character.db.FIRST_LOGIN:
|
||||||
|
# character.at_first_login()
|
||||||
|
# del character.db.FIRST_LOGIN
|
||||||
|
|
||||||
|
# # actually do the login, calling
|
||||||
|
# # customization hooks before and after.
|
||||||
|
# player.at_pre_login()
|
||||||
|
# character.at_pre_login()
|
||||||
|
|
||||||
|
# session.session_login(player)
|
||||||
|
|
||||||
|
# player.at_post_login()
|
||||||
|
# character.at_post_login()
|
||||||
|
# # run look
|
||||||
|
# #print "character:", character, character.scripts.all(), character.cmdset.current
|
||||||
|
# character.execute_cmd('look')
|
||||||
|
|
||||||
class CmdCreate(MuxCommand):
|
class CmdCreate(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
@ -173,17 +205,20 @@ class CmdCreate(MuxCommand):
|
||||||
if PlayerDB.objects.get_player_from_name(playername) or User.objects.filter(username=playername):
|
if PlayerDB.objects.get_player_from_name(playername) or User.objects.filter(username=playername):
|
||||||
# player already exists
|
# player already exists
|
||||||
session.msg("Sorry, there is already a player with the name '%s'." % playername)
|
session.msg("Sorry, there is already a player with the name '%s'." % playername)
|
||||||
elif PlayerDB.objects.get_player_from_email(email):
|
return
|
||||||
|
if PlayerDB.objects.get_player_from_email(email):
|
||||||
# email already set on a player
|
# email already set on a player
|
||||||
session.msg("Sorry, there is already a player with that email address.")
|
session.msg("Sorry, there is already a player with that email address.")
|
||||||
elif len(password) < 3:
|
return
|
||||||
|
if len(password) < 3:
|
||||||
# too short password
|
# too short password
|
||||||
string = "Your password must be at least 3 characters or longer."
|
string = "Your password must be at least 3 characters or longer."
|
||||||
string += "\n\rFor best security, make it at least 8 characters long, "
|
string += "\n\rFor best security, make it at least 8 characters long, "
|
||||||
string += "avoid making it a real word and mix numbers into it."
|
string += "avoid making it a real word and mix numbers into it."
|
||||||
session.msg(string)
|
session.msg(string)
|
||||||
else:
|
return
|
||||||
# everything's ok. Create the new player account
|
|
||||||
|
# everything's ok. Create the new player account.
|
||||||
try:
|
try:
|
||||||
default_home_id = ServerConfig.objects.conf("default_home")
|
default_home_id = ServerConfig.objects.conf("default_home")
|
||||||
default_home = ObjectDB.objects.get_id(default_home_id)
|
default_home = ObjectDB.objects.get_id(default_home_id)
|
||||||
|
|
@ -196,9 +231,14 @@ class CmdCreate(MuxCommand):
|
||||||
location=default_home,
|
location=default_home,
|
||||||
typeclass=typeclass,
|
typeclass=typeclass,
|
||||||
home=default_home)
|
home=default_home)
|
||||||
|
new_player = new_character.player
|
||||||
|
|
||||||
# character safety features
|
# character safety features
|
||||||
new_character.locks.delete("get")
|
new_character.locks.delete("get")
|
||||||
new_character.locks.add("get:perm(Wizards)")
|
new_character.locks.add("get:perm(Wizards)")
|
||||||
|
# allow the character itself and the player to puppet this character.
|
||||||
|
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
|
||||||
|
(new_character.id, new_player.id))
|
||||||
|
|
||||||
# set a default description
|
# set a default description
|
||||||
new_character.db.desc = "This is a Player."
|
new_character.db.desc = "This is a Player."
|
||||||
|
|
@ -219,8 +259,8 @@ class CmdCreate(MuxCommand):
|
||||||
string += "\n\nYou can now log with the command 'connect %s <your password>'."
|
string += "\n\nYou can now log with the command 'connect %s <your password>'."
|
||||||
session.msg(string % (playername, email, email))
|
session.msg(string % (playername, email, email))
|
||||||
except Exception:
|
except Exception:
|
||||||
# we have to handle traceback ourselves at this point, if
|
# We are in the middle between logged in and -not, so we have to handle tracebacks
|
||||||
# we don't, errors will give no feedback.
|
# ourselves at this point. If we don't, we won't see any errors at all.
|
||||||
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
|
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
|
||||||
session.msg(string % (traceback.format_exc()))
|
session.msg(string % (traceback.format_exc()))
|
||||||
logger.log_errmsg(traceback.format_exc())
|
logger.log_errmsg(traceback.format_exc())
|
||||||
|
|
|
||||||
|
|
@ -80,11 +80,16 @@ class ChannelCommand(command.Command):
|
||||||
msg = "[%s] %s: %s" % (channel.key, caller.name, msg)
|
msg = "[%s] %s: %s" % (channel.key, caller.name, msg)
|
||||||
# we can't use the utils.create function to make the Msg,
|
# we can't use the utils.create function to make the Msg,
|
||||||
# since that creates an import recursive loop.
|
# since that creates an import recursive loop.
|
||||||
msgobj = Msg(db_sender=caller.player, db_message=msg)
|
try:
|
||||||
|
sender = caller.player
|
||||||
|
except AttributeError:
|
||||||
|
# this could happen if a player is calling directly.
|
||||||
|
sender = caller.dbobj
|
||||||
|
msgobj = Msg(db_sender=sender, db_message=msg)
|
||||||
msgobj.save()
|
msgobj.save()
|
||||||
msgobj.channels = channel
|
msgobj.channels = channel
|
||||||
# send new message object to channel
|
# send new message object to channel
|
||||||
channel.msg(msgobj, from_obj=caller.player)
|
channel.msg(msgobj, from_obj=sender)
|
||||||
|
|
||||||
class ChannelHandler(object):
|
class ChannelHandler(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,16 @@ from src.utils import utils
|
||||||
|
|
||||||
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
|
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
|
||||||
|
|
||||||
|
def _to_player(accessing_obj):
|
||||||
|
"Helper function. Makes sure an accessing object is a player object"
|
||||||
|
if utils.inherits_from(accessing_obj, "src.objects.objects.Object"):
|
||||||
|
# an object. Convert to player.
|
||||||
|
accessing_obj = accessing_obj.player
|
||||||
|
return accessing_obj
|
||||||
|
|
||||||
|
|
||||||
|
# lock functions
|
||||||
|
|
||||||
def true(*args, **kwargs):
|
def true(*args, **kwargs):
|
||||||
"Always returns True."
|
"Always returns True."
|
||||||
return True
|
return True
|
||||||
|
|
@ -155,6 +165,29 @@ def perm_above(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
return any(True for hpos, hperm in enumerate(PERMISSION_HIERARCHY)
|
return any(True for hpos, hperm in enumerate(PERMISSION_HIERARCHY)
|
||||||
if hperm in [p.lower() for p in accessing_obj.permissions] and hpos > ppos)
|
if hperm in [p.lower() for p in accessing_obj.permissions] and hpos > ppos)
|
||||||
|
|
||||||
|
def pperm(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
The basic permission-checker for Player objects. Ignores case.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
pperm(<permission>)
|
||||||
|
|
||||||
|
where <permission> is the permission accessing_obj must
|
||||||
|
have in order to pass the lock. If the given permission
|
||||||
|
is part of PERMISSION_HIERARCHY, permission is also granted
|
||||||
|
to all ranks higher up in the hierarchy.
|
||||||
|
"""
|
||||||
|
return perm(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||||
|
|
||||||
|
def pperm_above(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Only allow Player objects with a permission *higher* in the permission
|
||||||
|
hierarchy than the one given. If there is no such higher rank,
|
||||||
|
it's assumed we refer to superuser. If no hierarchy is defined,
|
||||||
|
this function has no meaning and returns False.
|
||||||
|
"""
|
||||||
|
return perm_above(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||||
|
|
||||||
def dbref(accessing_obj, accessed_obj, *args, **kwargs):
|
def dbref(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Usage:
|
Usage:
|
||||||
|
|
@ -175,10 +208,21 @@ def dbref(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
return dbref == accessing_obj.id
|
return dbref == accessing_obj.id
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def pdbref(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Same as dbref, but making sure accessing_obj is a player.
|
||||||
|
"""
|
||||||
|
return dbref(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||||
|
|
||||||
def id(accessing_obj, accessed_obj, *args, **kwargs):
|
def id(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
"Alias to dbref"
|
"Alias to dbref"
|
||||||
return dbref(accessing_obj, accessed_obj, *args, **kwargs)
|
return dbref(accessing_obj, accessed_obj, *args, **kwargs)
|
||||||
|
|
||||||
|
def pid(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
|
"Alias to dbref, for Players"
|
||||||
|
return dbref(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def attr(accessing_obj, accessed_obj, *args, **kwargs):
|
def attr(accessing_obj, accessed_obj, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Usage:
|
Usage:
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,8 @@ class LockHandler(object):
|
||||||
wlist.append("Lock: access type '%s' changed from '%s' to '%s' " % \
|
wlist.append("Lock: access type '%s' changed from '%s' to '%s' " % \
|
||||||
(access_type, locks[access_type][2], raw_lockstring))
|
(access_type, locks[access_type][2], raw_lockstring))
|
||||||
locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring)
|
locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring)
|
||||||
if wlist:
|
if wlist and self.log_obj:
|
||||||
|
# not an error, so only report if log_obj is available.
|
||||||
self._log_error("\n".join(wlist))
|
self._log_error("\n".join(wlist))
|
||||||
if elist:
|
if elist:
|
||||||
raise LockException("\n".join(elist))
|
raise LockException("\n".join(elist))
|
||||||
|
|
@ -343,10 +344,11 @@ class LockHandler(object):
|
||||||
to None if the lock functions called don't access it). atype can also be
|
to None if the lock functions called don't access it). atype can also be
|
||||||
put to a dummy value since no lock selection is made.
|
put to a dummy value since no lock selection is made.
|
||||||
"""
|
"""
|
||||||
if (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'user')
|
if ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser)
|
||||||
and hasattr(accessing_obj.player.user, 'is_superuser')
|
or (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser)
|
||||||
and accessing_obj.player.user.is_superuser):
|
or (hasattr(accessing_obj, 'get_player') and (accessing_obj.get_player()==None or accessing_obj.get_player().is_superuser))):
|
||||||
return True # always grant access to the superuser.
|
return True
|
||||||
|
|
||||||
locks = self. _parse_lockstring(lockstring)
|
locks = self. _parse_lockstring(lockstring)
|
||||||
for access_type in locks:
|
for access_type in locks:
|
||||||
evalstring, func_tup, raw_string = locks[access_type]
|
evalstring, func_tup, raw_string = locks[access_type]
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,8 @@ from src.typeclasses.managers import returns_typeclass, returns_typeclass_list
|
||||||
from src.utils import utils
|
from src.utils import utils
|
||||||
|
|
||||||
# Try to use a custom way to parse id-tagged multimatches.
|
# Try to use a custom way to parse id-tagged multimatches.
|
||||||
IDPARSER_PATH = getattr(settings, 'ALTERNATE_OBJECT_SEARCH_MULTIMATCH_PARSER', 'src.objects.object_search_funcs')
|
|
||||||
if not IDPARSER_PATH:
|
AT_MULTIMATCH_INPUT = utils.mod_import(*settings.SEARCH_AT_MULTIMATCH_INPUT.rsplit('.', 1))
|
||||||
# can happen if variable is set to "" in settings
|
|
||||||
IDPARSER_PATH = 'src.objects.object_search_funcs'
|
|
||||||
exec("from %s import object_multimatch_parser as IDPARSER" % IDPARSER_PATH)
|
|
||||||
|
|
||||||
class ObjectManager(TypedObjectManager):
|
class ObjectManager(TypedObjectManager):
|
||||||
"""
|
"""
|
||||||
|
|
@ -172,7 +169,10 @@ class ObjectManager(TypedObjectManager):
|
||||||
global_search=False,
|
global_search=False,
|
||||||
attribute_name=None, location=None):
|
attribute_name=None, location=None):
|
||||||
"""
|
"""
|
||||||
Search as an object and return results.
|
Search as an object and return results. The result is always an Object.
|
||||||
|
If * is appended (player search, a Character controlled by this Player
|
||||||
|
is looked for. The Character is returned, not the Player. Use player_search
|
||||||
|
to find Player objects.
|
||||||
|
|
||||||
character: (Object) The object performing the search.
|
character: (Object) The object performing the search.
|
||||||
ostring: (string) The string to compare names against.
|
ostring: (string) The string to compare names against.
|
||||||
|
|
@ -187,7 +187,7 @@ class ObjectManager(TypedObjectManager):
|
||||||
if not ostring or not character:
|
if not ostring or not character:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not location:
|
if not location and hasattr(character, "location"):
|
||||||
location = character.location
|
location = character.location
|
||||||
|
|
||||||
# Easiest case - dbref matching (always exact)
|
# Easiest case - dbref matching (always exact)
|
||||||
|
|
@ -204,15 +204,16 @@ class ObjectManager(TypedObjectManager):
|
||||||
if character and ostring in ['me', 'self']:
|
if character and ostring in ['me', 'self']:
|
||||||
return [character]
|
return [character]
|
||||||
if character and ostring in ['*me', '*self']:
|
if character and ostring in ['*me', '*self']:
|
||||||
return [character.player]
|
return [character]
|
||||||
|
|
||||||
# Test if we are looking for a player object
|
# Test if we are looking for an object controlled by a
|
||||||
|
# specific player
|
||||||
|
|
||||||
if utils.to_unicode(ostring).startswith("*"):
|
if utils.to_unicode(ostring).startswith("*"):
|
||||||
# Player search - try to find obj by its player's name
|
# Player search - try to find obj by its player's name
|
||||||
player_match = self.get_object_with_player(ostring)
|
player_match = self.get_object_with_player(ostring)
|
||||||
if player_match is not None:
|
if player_match is not None:
|
||||||
return [player_match.player]
|
return [player_match]
|
||||||
|
|
||||||
# Search for keys, aliases or other attributes
|
# Search for keys, aliases or other attributes
|
||||||
|
|
||||||
|
|
@ -246,7 +247,7 @@ class ObjectManager(TypedObjectManager):
|
||||||
matches = local_and_global_search(ostring, exact=True)
|
matches = local_and_global_search(ostring, exact=True)
|
||||||
if not matches:
|
if not matches:
|
||||||
# if we have no match, check if we are dealing with an "N-keyword" query - if so, strip it.
|
# if we have no match, check if we are dealing with an "N-keyword" query - if so, strip it.
|
||||||
match_number, ostring = IDPARSER(ostring)
|
match_number, ostring = AT_MULTIMATCH_INPUT(ostring)
|
||||||
if match_number != None and ostring:
|
if match_number != None and ostring:
|
||||||
# Run search again, without match number:
|
# Run search again, without match number:
|
||||||
matches = local_and_global_search(ostring, exact=True)
|
matches = local_and_global_search(ostring, exact=True)
|
||||||
|
|
|
||||||
124
src/objects/migrations/0004_rename_nick_to_objectnick.py
Normal file
124
src/objects/migrations/0004_rename_nick_to_objectnick.py
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models, utils
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
|
||||||
|
try:
|
||||||
|
# if we migrate, we just rename the table. This will move over all values too.
|
||||||
|
db.rename_table("objects_nick", "objects_objectnick")
|
||||||
|
except utils.DatabaseError:
|
||||||
|
# this happens if we start from scratch. In that case the old
|
||||||
|
# database table doesn't exist, so we just create the new one.
|
||||||
|
|
||||||
|
# Adding model 'ObjectNick'
|
||||||
|
db.create_table('objects_objectnick', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('db_nick', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
|
||||||
|
('db_real', self.gf('django.db.models.fields.TextField')()),
|
||||||
|
('db_type', self.gf('django.db.models.fields.CharField')(default='inputline', max_length=16, null=True, blank=True)),
|
||||||
|
('db_obj', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['objects.ObjectDB'])),
|
||||||
|
))
|
||||||
|
db.send_create_signal('objects', ['ObjectNick'])
|
||||||
|
|
||||||
|
# Adding unique constraint on 'ObjectNick', fields ['db_nick', 'db_type', 'db_obj']
|
||||||
|
db.create_unique('objects_objectnick', ['db_nick', 'db_type', 'db_obj_id'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
raise RuntimeError("This migration cannot be reversed.")
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'auth.permission': {
|
||||||
|
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'objects.alias': {
|
||||||
|
'Meta': {'object_name': 'Alias'},
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'objects.objattribute': {
|
||||||
|
'Meta': {'object_name': 'ObjAttribute'},
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'objects.objectdb': {
|
||||||
|
'Meta': {'object_name': 'ObjectDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'objects.objectnick': {
|
||||||
|
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'},
|
||||||
|
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'players.playerdb': {
|
||||||
|
'Meta': {'object_name': 'PlayerDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['objects']
|
||||||
121
src/objects/migrations/0005_add_object_default_locks.py
Normal file
121
src/objects/migrations/0005_add_object_default_locks.py
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import DataMigration
|
||||||
|
from django.db import models, utils
|
||||||
|
|
||||||
|
class Migration(DataMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
"Write your forwards methods here."
|
||||||
|
|
||||||
|
# we need to add a default lock string to all objects, then a separate set to Characters.
|
||||||
|
|
||||||
|
lockstring1 = 'control:id(1);get:all();edit:perm(Wizards);examine:perm(Builders);call:true();puppet:id(#4) or perm(Immortals) or pperm(Immortals);delete:id(1) or perm(Wizards)'
|
||||||
|
lockstring2 = 'control:id(#3) or perm(Immortals);get:perm(Wizards);edit:perm(Wizards);examine:perm(Builders);call:false();puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals);delete:perm(Wizards)'
|
||||||
|
|
||||||
|
try:
|
||||||
|
for obj in orm.ObjectDB.objects.all().exclude(db_player__isnull=False):
|
||||||
|
obj.db_lock_storage = lockstring1
|
||||||
|
obj.save()
|
||||||
|
for obj in orm.ObjectDB.objects.filter(db_player__isnull=False):
|
||||||
|
obj.db_lock_storage = lockstring2 % (obj.id, obj.db_player.id)
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
except utils.DatabaseError:
|
||||||
|
# running from scatch. In this case we just ignore this.
|
||||||
|
pass
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
"Write your backwards methods here."
|
||||||
|
raise RuntimeError("You cannot reverse this migration.")
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'auth.permission': {
|
||||||
|
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'objects.alias': {
|
||||||
|
'Meta': {'object_name': 'Alias'},
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'objects.objattribute': {
|
||||||
|
'Meta': {'object_name': 'ObjAttribute'},
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'objects.objectdb': {
|
||||||
|
'Meta': {'object_name': 'ObjectDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'objects.objectnick': {
|
||||||
|
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'},
|
||||||
|
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'players.playerdb': {
|
||||||
|
'Meta': {'object_name': 'PlayerDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['objects']
|
||||||
|
|
@ -16,25 +16,24 @@ transparently through the decorating TypeClass.
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from src.utils.idmapper.models import SharedMemoryModel
|
from src.utils.idmapper.models import SharedMemoryModel
|
||||||
from src.typeclasses.models import Attribute, TypedObject
|
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||||
from src.typeclasses.typeclass import TypeClass
|
from src.typeclasses.typeclass import TypeClass
|
||||||
from src.objects.manager import ObjectManager
|
from src.objects.manager import ObjectManager
|
||||||
|
from src.players.models import PlayerDB
|
||||||
from src.server.models import ServerConfig
|
from src.server.models import ServerConfig
|
||||||
from src.commands.cmdsethandler import CmdSetHandler
|
from src.commands.cmdsethandler import CmdSetHandler
|
||||||
|
from src.commands import cmdhandler
|
||||||
from src.scripts.scripthandler import ScriptHandler
|
from src.scripts.scripthandler import ScriptHandler
|
||||||
from src.utils import logger
|
from src.utils import logger
|
||||||
from src.utils.utils import is_iter, to_unicode
|
from src.utils.utils import is_iter, to_unicode, to_str, mod_import
|
||||||
|
|
||||||
|
#PlayerDB = ContentType.objects.get(app_label="players", model="playerdb").model_class()
|
||||||
|
|
||||||
FULL_PERSISTENCE = settings.FULL_PERSISTENCE
|
FULL_PERSISTENCE = settings.FULL_PERSISTENCE
|
||||||
|
AT_SEARCH_RESULT = mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||||
try:
|
|
||||||
HANDLE_SEARCH_ERRORS = __import__(
|
|
||||||
settings.ALTERNATE_OBJECT_SEARCH_ERROR_HANDLER).handle_search_errors, fromlist=[None]
|
|
||||||
except Exception:
|
|
||||||
from src.objects.object_search_funcs \
|
|
||||||
import handle_search_errors as HANDLE_SEARCH_ERRORS
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -80,80 +79,33 @@ class Alias(SharedMemoryModel):
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Nick
|
# Object Nicks
|
||||||
#
|
#
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
class Nick(SharedMemoryModel):
|
class ObjectNick(TypeNick):
|
||||||
"""
|
"""
|
||||||
This model holds whichever alternate names this object
|
|
||||||
has for OTHER objects, but also for arbitrary strings,
|
|
||||||
channels, players etc. Setting a nick does not affect
|
|
||||||
the nicknamed object at all (as opposed to Aliases above),
|
|
||||||
and only this object will be able to refer to the nicknamed
|
|
||||||
object by the given nick.
|
|
||||||
|
|
||||||
The default nick types used by Evennia are:
|
The default nick types used by Evennia are:
|
||||||
inputline (default) - match against all input
|
inputline (default) - match against all input
|
||||||
player - match against player searches
|
player - match against player searches
|
||||||
obj - match against object searches
|
obj - match against object searches
|
||||||
channel - used to store own names for channels
|
channel - used to store own names for channels
|
||||||
|
|
||||||
"""
|
"""
|
||||||
db_nick = models.CharField(max_length=255, db_index=True) # the nick
|
|
||||||
db_real = models.TextField() # the aliased string
|
|
||||||
db_type = models.CharField(default="inputline", max_length=16, null=True, blank=True) # the type of nick
|
|
||||||
db_obj = models.ForeignKey("ObjectDB")
|
db_obj = models.ForeignKey("ObjectDB")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"Define Django meta options"
|
"Define Django meta options"
|
||||||
verbose_name = "Nickname"
|
verbose_name = "Nickname for Objects"
|
||||||
verbose_name_plural = "Nicknames"
|
verbose_name_plural = "Nicknames Objects"
|
||||||
unique_together = ("db_nick", "db_type", "db_obj")
|
unique_together = ("db_nick", "db_type", "db_obj")
|
||||||
|
|
||||||
class NickHandler(object):
|
class ObjectNickHandler(TypeNickHandler):
|
||||||
"""
|
"""
|
||||||
Handles nick access and setting. Accessed through ObjectDB.nicks
|
Handles nick access and setting. Accessed through ObjectDB.nicks
|
||||||
"""
|
"""
|
||||||
|
NickClass = ObjectNick
|
||||||
|
|
||||||
def __init__(self, obj):
|
|
||||||
"Setup"
|
|
||||||
self.obj = obj
|
|
||||||
|
|
||||||
def add(self, nick, realname, nick_type="inputline"):
|
|
||||||
"We want to assign a new nick"
|
|
||||||
if not nick or not nick.strip():
|
|
||||||
return
|
|
||||||
nick = nick.strip()
|
|
||||||
real = realname.strip()
|
|
||||||
query = Nick.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
|
|
||||||
if query.count():
|
|
||||||
old_nick = query[0]
|
|
||||||
old_nick.db_real = real
|
|
||||||
old_nick.save()
|
|
||||||
else:
|
|
||||||
new_nick = Nick(db_nick=nick, db_real=real, db_type=nick_type, db_obj=self.obj)
|
|
||||||
new_nick.save()
|
|
||||||
def delete(self, nick, nick_type="inputline"):
|
|
||||||
"Removes a nick"
|
|
||||||
nick = nick.strip()
|
|
||||||
query = Nick.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
|
|
||||||
if query.count():
|
|
||||||
# remove the found nick(s)
|
|
||||||
query.delete()
|
|
||||||
def get(self, nick=None, nick_type="inputline"):
|
|
||||||
if nick:
|
|
||||||
query = Nick.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
|
|
||||||
query = query.values_list("db_real", flat=True)
|
|
||||||
if query.count():
|
|
||||||
return query[0]
|
|
||||||
else:
|
|
||||||
return nick
|
|
||||||
else:
|
|
||||||
return Nick.objects.filter(db_obj=self.obj)
|
|
||||||
def has(self, nick, nick_type="inputline"):
|
|
||||||
"Returns true/false if this nick is defined or not"
|
|
||||||
return Nick.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type).count()
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -239,7 +191,7 @@ class ObjectDB(TypedObject):
|
||||||
self.cmdset.update(init_mode=True)
|
self.cmdset.update(init_mode=True)
|
||||||
self.scripts = ScriptHandler(self)
|
self.scripts = ScriptHandler(self)
|
||||||
self.scripts.validate(init_mode=True)
|
self.scripts.validate(init_mode=True)
|
||||||
self.nicks = NickHandler(self)
|
self.nicks = ObjectNickHandler(self)
|
||||||
|
|
||||||
# Wrapper properties to easily set database fields. These are
|
# Wrapper properties to easily set database fields. These are
|
||||||
# @property decorators that allows to access these fields using
|
# @property decorators that allows to access these fields using
|
||||||
|
|
@ -312,7 +264,7 @@ class ObjectDB(TypedObject):
|
||||||
loc = location
|
loc = location
|
||||||
elif ObjectDB.objects.dbref(location):
|
elif ObjectDB.objects.dbref(location):
|
||||||
# location is a dbref; search
|
# location is a dbref; search
|
||||||
loc = ObjectDB.objects.dbref_search(location)
|
loc = ObjectDB.objects.dbref_search(ocation)
|
||||||
if loc and hasattr(loc,'dbobj'):
|
if loc and hasattr(loc,'dbobj'):
|
||||||
loc = loc.dbobj
|
loc = loc.dbobj
|
||||||
else:
|
else:
|
||||||
|
|
@ -524,14 +476,11 @@ class ObjectDB(TypedObject):
|
||||||
global_search=False,
|
global_search=False,
|
||||||
attribute_name=None,
|
attribute_name=None,
|
||||||
use_nicks=False, location=None,
|
use_nicks=False, location=None,
|
||||||
ignore_errors=False):
|
ignore_errors=False, player=False):
|
||||||
"""
|
"""
|
||||||
Perform a standard object search in the database, handling
|
Perform a standard object search in the database, handling
|
||||||
multiple results and lack thereof gracefully.
|
multiple results and lack thereof gracefully.
|
||||||
|
|
||||||
if local_only AND search_self are both false, a global
|
|
||||||
search is done instead.
|
|
||||||
|
|
||||||
ostring: (str) The string to match object names against.
|
ostring: (str) The string to match object names against.
|
||||||
Obs - To find a player, append * to the
|
Obs - To find a player, append * to the
|
||||||
start of ostring.
|
start of ostring.
|
||||||
|
|
@ -544,6 +493,15 @@ class ObjectDB(TypedObject):
|
||||||
ignore_errors : Don't display any error messages even
|
ignore_errors : Don't display any error messages even
|
||||||
if there are none/multiple matches -
|
if there are none/multiple matches -
|
||||||
just return the result as a list.
|
just return the result as a list.
|
||||||
|
player : Don't search for an Object but a Player.
|
||||||
|
This will also find players that don't
|
||||||
|
currently have a character.
|
||||||
|
|
||||||
|
Use *<string> to search for objects controlled by a specific
|
||||||
|
player. Note that the object controlled by the player will be
|
||||||
|
returned, not the player object itself. This also means that
|
||||||
|
this will not find Players without a character. Use the keyword
|
||||||
|
player=True to find player objects.
|
||||||
|
|
||||||
Note - for multiple matches, the engine accepts a number
|
Note - for multiple matches, the engine accepts a number
|
||||||
linked to the key in order to separate the matches from
|
linked to the key in order to separate the matches from
|
||||||
|
|
@ -554,13 +512,21 @@ class ObjectDB(TypedObject):
|
||||||
etc.
|
etc.
|
||||||
"""
|
"""
|
||||||
if use_nicks:
|
if use_nicks:
|
||||||
if ostring.startswith('*'):
|
if ostring.startswith('*') or player:
|
||||||
# player nick replace
|
# player nick replace
|
||||||
ostring = "*%s" % self.nicks.get(ostring.lstrip('*'), nick_type="player")
|
ostring = self.nicks.get(ostring.lstrip('*'), nick_type="player")
|
||||||
|
if not player:
|
||||||
|
ostring = "*%s" % ostring
|
||||||
else:
|
else:
|
||||||
# object nick replace
|
# object nick replace
|
||||||
ostring = self.nicks.get(ostring, nick_type="object")
|
ostring = self.nicks.get(ostring, nick_type="object")
|
||||||
|
|
||||||
|
if player:
|
||||||
|
if ostring in ("me", "self", "*me", "*self"):
|
||||||
|
results = [self.player]
|
||||||
|
else:
|
||||||
|
results = PlayerDB.objects.player_search(ostring.lstrip('*'))
|
||||||
|
else:
|
||||||
results = ObjectDB.objects.object_search(self, ostring,
|
results = ObjectDB.objects.object_search(self, ostring,
|
||||||
global_search=global_search,
|
global_search=global_search,
|
||||||
attribute_name=attribute_name,
|
attribute_name=attribute_name,
|
||||||
|
|
@ -568,8 +534,8 @@ class ObjectDB(TypedObject):
|
||||||
|
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
return results
|
return results
|
||||||
return HANDLE_SEARCH_ERRORS(self, ostring, results, global_search)
|
# this import is cache after the first call.
|
||||||
|
return AT_SEARCH_RESULT(self, ostring, results, global_search)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Execution/action methods
|
# Execution/action methods
|
||||||
|
|
@ -588,7 +554,7 @@ class ObjectDB(TypedObject):
|
||||||
|
|
||||||
raw_list = raw_string.split(None)
|
raw_list = raw_string.split(None)
|
||||||
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
|
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
|
||||||
for nick in Nick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
|
for nick in ObjectNick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
|
||||||
if nick.db_nick in raw_list:
|
if nick.db_nick in raw_list:
|
||||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||||
break
|
break
|
||||||
|
|
@ -796,9 +762,15 @@ class ObjectDB(TypedObject):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# See if we need to kick the player off.
|
# See if we need to kick the player off.
|
||||||
|
|
||||||
for session in self.sessions:
|
for session in self.sessions:
|
||||||
session.msg("Your character %s has been destroyed. Goodbye." % self.name)
|
session.msg("Your character %s has been destroyed." % self.name)
|
||||||
session.session_disconnect()
|
#session.session_disconnect()
|
||||||
|
|
||||||
|
# sever the connection (important!)
|
||||||
|
if object.__getattribute__(self, 'player') and self.player:
|
||||||
|
self.player.character = None
|
||||||
|
self.player = None
|
||||||
|
|
||||||
# if self.player:
|
# if self.player:
|
||||||
# self.player.user.is_active = False
|
# self.player.user.is_active = False
|
||||||
|
|
@ -811,6 +783,3 @@ class ObjectDB(TypedObject):
|
||||||
# Perform the deletion of the object
|
# Perform the deletion of the object
|
||||||
super(ObjectDB, self).delete()
|
super(ObjectDB, self).delete()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Deferred import to avoid circular import errors.
|
|
||||||
from src.commands import cmdhandler
|
|
||||||
|
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
"""
|
|
||||||
Default functions for formatting and processing object searches.
|
|
||||||
|
|
||||||
This is in its own module due to them being possible to
|
|
||||||
replace from the settings file by use of setting the variables
|
|
||||||
|
|
||||||
ALTERNATE_OBJECT_SEARCH_ERROR_HANDLER
|
|
||||||
ALTERNATE_OBJECT_SEARCH_MULTIMATCH_PARSER
|
|
||||||
|
|
||||||
Both the replacing functions must have the same name and same input/output
|
|
||||||
as the ones in this module.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def handle_search_errors(emit_to_obj, ostring, results, global_search=False):
|
|
||||||
"""
|
|
||||||
Takes a search result (a list) and
|
|
||||||
formats eventual errors.
|
|
||||||
|
|
||||||
emit_to_obj - object to receive feedback.
|
|
||||||
ostring - original search string
|
|
||||||
results - list of object matches, if any
|
|
||||||
global_search - if this was a global_search or not
|
|
||||||
(if it is, there might be an idea of supplying
|
|
||||||
dbrefs instead of only numbers)
|
|
||||||
"""
|
|
||||||
if not results:
|
|
||||||
emit_to_obj.msg("Could not find '%s'." % ostring)
|
|
||||||
return None
|
|
||||||
if len(results) > 1:
|
|
||||||
# we have more than one match. We will display a
|
|
||||||
# list of the form 1-objname, 2-objname etc.
|
|
||||||
|
|
||||||
# check if the emit_to_object may se dbrefs
|
|
||||||
show_dbref = global_search and \
|
|
||||||
emit_to_obj.check_permstring('Builders')
|
|
||||||
|
|
||||||
string = "More than one match for '%s'" % ostring
|
|
||||||
string += " (please narrow target):"
|
|
||||||
for num, result in enumerate(results):
|
|
||||||
invtext = ""
|
|
||||||
dbreftext = ""
|
|
||||||
if result.location == emit_to_obj:
|
|
||||||
invtext = " (carried)"
|
|
||||||
if show_dbref:
|
|
||||||
dbreftext = "(#%i)" % result.id
|
|
||||||
string += "\n %i-%s%s%s" % (num+1, result.name,
|
|
||||||
dbreftext, invtext)
|
|
||||||
emit_to_obj.msg(string.strip())
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return results[0]
|
|
||||||
|
|
||||||
def object_multimatch_parser(ostring):
|
|
||||||
"""
|
|
||||||
Parse number-identifiers.
|
|
||||||
|
|
||||||
Sometimes it can happen that there are several objects in the room
|
|
||||||
all with exactly the same key/identifier. Showing dbrefs to
|
|
||||||
separate them is not suitable for all types of games since it's
|
|
||||||
unique to that object (and e.g. in rp-games the object might not
|
|
||||||
want to be identified like that). Instead Evennia allows for
|
|
||||||
dbref-free matching by letting the user number which of the
|
|
||||||
objects in a multi-match they want.
|
|
||||||
|
|
||||||
Ex for use in game session:
|
|
||||||
|
|
||||||
> look
|
|
||||||
You see: ball, ball, ball and ball.
|
|
||||||
> get ball
|
|
||||||
There where multiple matches for ball:
|
|
||||||
1-ball
|
|
||||||
2-ball
|
|
||||||
3-ball
|
|
||||||
4-ball
|
|
||||||
> get 3-ball
|
|
||||||
You get the ball.
|
|
||||||
|
|
||||||
The actual feedback upon multiple matches has to be
|
|
||||||
handled by the searching command. The syntax shown above is the
|
|
||||||
default.
|
|
||||||
|
|
||||||
For replacing, the method must be named the same and
|
|
||||||
take the searchstring as argument and
|
|
||||||
return a tuple (int, string) where int is the identifier
|
|
||||||
matching which of the results (in order) should be used to
|
|
||||||
pick out the right match from the multimatch). Note
|
|
||||||
that the engine assumes this number to start with 1 (i.e. not
|
|
||||||
zero as in normal Python).
|
|
||||||
"""
|
|
||||||
if not isinstance(ostring, basestring):
|
|
||||||
return (None, ostring)
|
|
||||||
if not '-' in ostring:
|
|
||||||
return (None, ostring)
|
|
||||||
try:
|
|
||||||
index = ostring.find('-')
|
|
||||||
number = int(ostring[:index])-1
|
|
||||||
return (number, ostring[index+1:])
|
|
||||||
except ValueError:
|
|
||||||
#not a number; this is not an identifier.
|
|
||||||
return (None, ostring)
|
|
||||||
except IndexError:
|
|
||||||
return (None, ostring)
|
|
||||||
|
|
@ -49,6 +49,9 @@ class Object(TypeClass):
|
||||||
"""
|
"""
|
||||||
This sets up the default properties of an Object,
|
This sets up the default properties of an Object,
|
||||||
just before the more general at_object_creation.
|
just before the more general at_object_creation.
|
||||||
|
|
||||||
|
Don't change this, instead edit at_object_creation() to
|
||||||
|
overload the defaults (it is called after this one).
|
||||||
"""
|
"""
|
||||||
# the default security setup fallback for a generic
|
# the default security setup fallback for a generic
|
||||||
# object. Overload in child for a custom setup. Also creation
|
# object. Overload in child for a custom setup. Also creation
|
||||||
|
|
@ -63,6 +66,7 @@ class Object(TypeClass):
|
||||||
self.locks.add("delete:perm(Wizards)") # delete object
|
self.locks.add("delete:perm(Wizards)") # delete object
|
||||||
self.locks.add("get:all()") # pick up object
|
self.locks.add("get:all()") # pick up object
|
||||||
self.locks.add("call:true()") # allow to call commands on this object
|
self.locks.add("call:true()") # allow to call commands on this object
|
||||||
|
self.locks.add("puppet:id(%s) or perm(Immortals) or pperm(Immortals)" % dbref) # restricts puppeting of this object
|
||||||
|
|
||||||
def at_object_creation(self):
|
def at_object_creation(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -310,9 +314,11 @@ class Character(Object):
|
||||||
def basetype_setup(self):
|
def basetype_setup(self):
|
||||||
"""
|
"""
|
||||||
Setup character-specific security
|
Setup character-specific security
|
||||||
|
|
||||||
|
Don't change this, instead edit at_object_creation() to
|
||||||
|
overload the defaults (it is called after this one).
|
||||||
"""
|
"""
|
||||||
super(Character, self).basetype_setup()
|
super(Character, self).basetype_setup()
|
||||||
self.locks.add("puppet:id(%s) or perm(Immortals)" % self.dbobj.dbref) # who may become this object's player
|
|
||||||
self.locks.add("get:false()") # noone can pick up the character
|
self.locks.add("get:false()") # noone can pick up the character
|
||||||
self.locks.add("call:false()") # no commands can be called on character
|
self.locks.add("call:false()") # no commands can be called on character
|
||||||
|
|
||||||
|
|
@ -348,9 +354,13 @@ class Room(Object):
|
||||||
"""
|
"""
|
||||||
Simple setup, shown as an example
|
Simple setup, shown as an example
|
||||||
(since default is None anyway)
|
(since default is None anyway)
|
||||||
|
|
||||||
|
Don't change this, instead edit at_object_creation() to
|
||||||
|
overload the defaults (it is called after this one).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super(Room, self).basetype_setup()
|
super(Room, self).basetype_setup()
|
||||||
|
self.locks.add("puppet:false()") # would be weird to puppet a room ...
|
||||||
self.locks.add("get:false()")
|
self.locks.add("get:false()")
|
||||||
|
|
||||||
super(Room, self).basetype_setup()
|
super(Room, self).basetype_setup()
|
||||||
|
|
@ -371,9 +381,13 @@ class Exit(Object):
|
||||||
def basetype_setup(self):
|
def basetype_setup(self):
|
||||||
"""
|
"""
|
||||||
Setup exit-security
|
Setup exit-security
|
||||||
|
|
||||||
|
Don't change this, instead edit at_object_creation() to
|
||||||
|
overload the defaults (it is called after this one).
|
||||||
"""
|
"""
|
||||||
# the lock is open to all by default
|
# the lock is open to all by default
|
||||||
super(Exit, self).basetype_setup()
|
super(Exit, self).basetype_setup()
|
||||||
|
self.locks.add("puppet:false()") # would be weird to puppet an exit ...
|
||||||
self.locks.add("traverse:all()") # who can pass through exit
|
self.locks.add("traverse:all()") # who can pass through exit
|
||||||
self.locks.add("get:false()") # noone can pick up the exit
|
self.locks.add("get:false()") # noone can pick up the exit
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,17 +146,13 @@ class PlayerManager(TypedObjectManager):
|
||||||
|
|
||||||
ostring = a string or database id.
|
ostring = a string or database id.
|
||||||
"""
|
"""
|
||||||
players = []
|
ostring = ostring.lstrip("*")
|
||||||
try:
|
dbref = self.dbref(ostring)
|
||||||
# try dbref match
|
if dbref:
|
||||||
dbref = int(ostring.strip('#'))
|
matches = self.filter(id=dbref)
|
||||||
players = self.filter(id=dbref)
|
if matches:
|
||||||
except Exception:
|
return matches
|
||||||
pass
|
return self.filter(user__username__iexact=ostring)
|
||||||
if not players:
|
|
||||||
players = self.filter(user__username=ostring)
|
|
||||||
return players
|
|
||||||
|
|
||||||
|
|
||||||
def swap_character(self, player, new_character, delete_old_character=False):
|
def swap_character(self, player, new_character, delete_old_character=False):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
|
||||||
|
# Adding field 'PlayerDB.db_cmdset_storage'
|
||||||
|
db.add_column('players_playerdb', 'db_cmdset_storage', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
|
||||||
|
# Deleting field 'PlayerDB.db_cmdset_storage'
|
||||||
|
db.delete_column('players_playerdb', 'db_cmdset_storage')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'auth.permission': {
|
||||||
|
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'objects.objectdb': {
|
||||||
|
'Meta': {'object_name': 'ObjectDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'players.playerattribute': {
|
||||||
|
'Meta': {'object_name': 'PlayerAttribute'},
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||||
|
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'players.playerdb': {
|
||||||
|
'Meta': {'object_name': 'PlayerDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['players']
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
|
||||||
|
# Adding model 'PlayerNick'
|
||||||
|
db.create_table('players_playernick', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('db_nick', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
|
||||||
|
('db_real', self.gf('django.db.models.fields.TextField')()),
|
||||||
|
('db_type', self.gf('django.db.models.fields.CharField')(default='inputline', max_length=16, null=True, blank=True)),
|
||||||
|
('db_obj', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['players.PlayerDB'])),
|
||||||
|
))
|
||||||
|
db.send_create_signal('players', ['PlayerNick'])
|
||||||
|
|
||||||
|
# Adding unique constraint on 'PlayerNick', fields ['db_nick', 'db_type', 'db_obj']
|
||||||
|
db.create_unique('players_playernick', ['db_nick', 'db_type', 'db_obj_id'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
|
||||||
|
# Removing unique constraint on 'PlayerNick', fields ['db_nick', 'db_type', 'db_obj']
|
||||||
|
db.delete_unique('players_playernick', ['db_nick', 'db_type', 'db_obj_id'])
|
||||||
|
|
||||||
|
# Deleting model 'PlayerNick'
|
||||||
|
db.delete_table('players_playernick')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'auth.permission': {
|
||||||
|
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'objects.objectdb': {
|
||||||
|
'Meta': {'object_name': 'ObjectDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'players.playerattribute': {
|
||||||
|
'Meta': {'object_name': 'PlayerAttribute'},
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||||
|
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'players.playerdb': {
|
||||||
|
'Meta': {'object_name': 'PlayerDB'},
|
||||||
|
'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||||
|
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True'}),
|
||||||
|
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||||
|
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||||
|
},
|
||||||
|
'players.playernick': {
|
||||||
|
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'},
|
||||||
|
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||||
|
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||||
|
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['players']
|
||||||
|
|
@ -44,10 +44,16 @@ from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from src.server.sessionhandler import SESSIONS
|
from src.server.sessionhandler import SESSIONS
|
||||||
from src.players import manager
|
from src.players import manager
|
||||||
from src.typeclasses.models import Attribute, TypedObject
|
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||||
from src.utils import logger
|
from src.utils import logger, utils
|
||||||
|
from src.commands.cmdsethandler import CmdSetHandler
|
||||||
|
from src.commands import cmdhandler
|
||||||
|
|
||||||
|
AT_SEARCH_RESULT = utils.mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -68,6 +74,36 @@ class PlayerAttribute(Attribute):
|
||||||
verbose_name = "Player Attribute"
|
verbose_name = "Player Attribute"
|
||||||
verbose_name_plural = "Player Attributes"
|
verbose_name_plural = "Player Attributes"
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Player Nicks
|
||||||
|
#
|
||||||
|
#------------------------------------------------------------
|
||||||
|
|
||||||
|
class PlayerNick(TypeNick):
|
||||||
|
"""
|
||||||
|
|
||||||
|
The default nick types used by Evennia are:
|
||||||
|
inputline (default) - match against all input
|
||||||
|
player - match against player searches
|
||||||
|
obj - match against object searches
|
||||||
|
channel - used to store own names for channels
|
||||||
|
"""
|
||||||
|
db_obj = models.ForeignKey("PlayerDB")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"Define Django meta options"
|
||||||
|
verbose_name = "Nickname for Players"
|
||||||
|
verbose_name_plural = "Nicknames Players"
|
||||||
|
unique_together = ("db_nick", "db_type", "db_obj")
|
||||||
|
|
||||||
|
class PlayerNickHandler(TypeNickHandler):
|
||||||
|
"""
|
||||||
|
Handles nick access and setting. Accessed through ObjectDB.nicks
|
||||||
|
"""
|
||||||
|
NickClass = PlayerNick
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# PlayerDB
|
# PlayerDB
|
||||||
|
|
@ -117,12 +153,23 @@ class PlayerDB(TypedObject):
|
||||||
# Use the property 'obj' to access.
|
# Use the property 'obj' to access.
|
||||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True)
|
db_obj = models.ForeignKey("objects.ObjectDB", null=True)
|
||||||
|
|
||||||
|
# database storage of persistant cmdsets.
|
||||||
|
db_cmdset_storage = models.TextField(null=True)
|
||||||
|
|
||||||
# Database manager
|
# Database manager
|
||||||
objects = manager.PlayerManager()
|
objects = manager.PlayerManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'players'
|
app_label = 'players'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"Parent must be initiated first"
|
||||||
|
TypedObject.__init__(self, *args, **kwargs)
|
||||||
|
# handlers
|
||||||
|
self.cmdset = CmdSetHandler(self)
|
||||||
|
self.cmdset.update(init_mode=True)
|
||||||
|
self.nicks = PlayerNickHandler(self)
|
||||||
|
|
||||||
# Wrapper properties to easily set database fields. These are
|
# Wrapper properties to easily set database fields. These are
|
||||||
# @property decorators that allows to access these fields using
|
# @property decorators that allows to access these fields using
|
||||||
# normal python operations (without having to remember to save()
|
# normal python operations (without having to remember to save()
|
||||||
|
|
@ -172,6 +219,26 @@ class PlayerDB(TypedObject):
|
||||||
self.db_obj = None
|
self.db_obj = None
|
||||||
self.save()
|
self.save()
|
||||||
character = property(character_get, character_set, character_del)
|
character = property(character_get, character_set, character_del)
|
||||||
|
# cmdset_storage property
|
||||||
|
#@property
|
||||||
|
def cmdset_storage_get(self):
|
||||||
|
"Getter. Allows for value = self.name. Returns a list of cmdset_storage."
|
||||||
|
if self.db_cmdset_storage:
|
||||||
|
return [path.strip() for path in self.db_cmdset_storage.split(',')]
|
||||||
|
return []
|
||||||
|
#@cmdset_storage.setter
|
||||||
|
def cmdset_storage_set(self, value):
|
||||||
|
"Setter. Allows for self.name = value. Stores as a comma-separated string."
|
||||||
|
if utils.is_iter(value):
|
||||||
|
value = ",".join([str(val).strip() for val in value])
|
||||||
|
self.db_cmdset_storage = value
|
||||||
|
self.save()
|
||||||
|
#@cmdset_storage.deleter
|
||||||
|
def cmdset_storage_del(self):
|
||||||
|
"Deleter. Allows for del self.name"
|
||||||
|
self.db_cmdset_storage = ""
|
||||||
|
self.save()
|
||||||
|
cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"Define Django meta options"
|
"Define Django meta options"
|
||||||
|
|
@ -245,19 +312,73 @@ class PlayerDB(TypedObject):
|
||||||
Evennia -> User
|
Evennia -> User
|
||||||
This is the main route for sending data back to the user from the server.
|
This is the main route for sending data back to the user from the server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if from_obj:
|
if from_obj:
|
||||||
try:
|
try:
|
||||||
from_obj.at_msg_send(outgoing_string, to_obj=self, data=data)
|
from_obj.at_msg_send(outgoing_string, to_obj=self, data=data)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if object.__getattribute__(self, "character"):
|
|
||||||
if self.character.at_msg_receive(outgoing_string, from_obj=from_obj, data=data):
|
if (object.__getattribute__(self, "character")
|
||||||
|
and not self.character.at_msg_receive(outgoing_string, from_obj=from_obj, data=data)):
|
||||||
|
# the at_msg_receive() hook may block receiving of certain messages
|
||||||
|
return
|
||||||
|
|
||||||
|
outgoing_string = utils.to_str(outgoing_string, force_string=True)
|
||||||
|
|
||||||
for session in object.__getattribute__(self, 'sessions'):
|
for session in object.__getattribute__(self, 'sessions'):
|
||||||
session.msg(outgoing_string, data)
|
session.msg(outgoing_string, data)
|
||||||
|
|
||||||
|
|
||||||
def swap_character(self, new_character, delete_old_character=False):
|
def swap_character(self, new_character, delete_old_character=False):
|
||||||
"""
|
"""
|
||||||
Swaps character, if possible
|
Swaps character, if possible
|
||||||
"""
|
"""
|
||||||
return self.__class__.objects.swap_character(self, new_character, delete_old_character=delete_old_character)
|
return self.__class__.objects.swap_character(self, new_character, delete_old_character=delete_old_character)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Execution/action methods
|
||||||
|
#
|
||||||
|
|
||||||
|
def execute_cmd(self, raw_string):
|
||||||
|
"""
|
||||||
|
Do something as this playe. This command transparently
|
||||||
|
lets its typeclass execute the command.
|
||||||
|
raw_string - raw command input coming from the command line.
|
||||||
|
"""
|
||||||
|
# nick replacement - we require full-word matching.
|
||||||
|
|
||||||
|
raw_string = utils.to_unicode(raw_string)
|
||||||
|
|
||||||
|
raw_list = raw_string.split(None)
|
||||||
|
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
|
||||||
|
for nick in PlayerNick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
|
||||||
|
if nick.db_nick in raw_list:
|
||||||
|
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||||
|
break
|
||||||
|
cmdhandler.cmdhandler(self.typeclass(self), raw_string)
|
||||||
|
|
||||||
|
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
|
||||||
|
location=None, ignore_errors=False, player=False):
|
||||||
|
"""
|
||||||
|
A shell method mimicking the ObjectDB equivalent, for easy inclusion from
|
||||||
|
commands regardless of if the command is run by a Player or an Object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.character:
|
||||||
|
# run the normal search
|
||||||
|
return self.character.search(ostring, global_search=global_search, attribute_name=attribute_name,
|
||||||
|
use_nicks=use_nicks, location=location,
|
||||||
|
ignore_errors=ignore_errors, player=player)
|
||||||
|
if player:
|
||||||
|
# seach for players
|
||||||
|
matches = self.__class__.objects.player_search(ostring)
|
||||||
|
else:
|
||||||
|
# more limited player-only search. Still returns an Object.
|
||||||
|
ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
|
||||||
|
matches = ObjectDB.objects.object_search(self, ostring, global_search=global_search)
|
||||||
|
# deal with results
|
||||||
|
matches = AT_SEARCH_RESULT(self, ostring, matches, global_search=global_search)
|
||||||
|
return matches
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,19 @@ instead for most things).
|
||||||
"""
|
"""
|
||||||
from src.typeclasses.typeclass import TypeClass
|
from src.typeclasses.typeclass import TypeClass
|
||||||
|
|
||||||
|
from settings import CMDSET_OOC
|
||||||
|
|
||||||
class Player(TypeClass):
|
class Player(TypeClass):
|
||||||
"""
|
"""
|
||||||
Base typeclass for all Players.
|
Base typeclass for all Players.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def at_player_creation(self):
|
def basetype_setup(self):
|
||||||
"""
|
"""
|
||||||
This is called once, the very first time
|
This sets up the basic properties for a player.
|
||||||
the player is created (i.e. first time they
|
Overload this with at_player_creation rather than
|
||||||
register with the game). It's a good place
|
changing this method.
|
||||||
to store attributes all players should have,
|
|
||||||
like configuration values etc.
|
|
||||||
"""
|
"""
|
||||||
# the text encoding to use.
|
# the text encoding to use.
|
||||||
self.db.encoding = "utf-8"
|
self.db.encoding = "utf-8"
|
||||||
|
|
@ -35,6 +36,21 @@ class Player(TypeClass):
|
||||||
self.locks.add("boot:perm(Wizards)")
|
self.locks.add("boot:perm(Wizards)")
|
||||||
self.locks.add("msg:all()")
|
self.locks.add("msg:all()")
|
||||||
|
|
||||||
|
# The ooc player cmdset
|
||||||
|
self.cmdset.add_default(CMDSET_OOC, permanent=True)
|
||||||
|
self.cmdset.outside_access = False
|
||||||
|
|
||||||
|
def at_player_creation(self):
|
||||||
|
"""
|
||||||
|
This is called once, the very first time
|
||||||
|
the player is created (i.e. first time they
|
||||||
|
register with the game). It's a good place
|
||||||
|
to store attributes all players should have,
|
||||||
|
like configuration values etc.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Note that the hooks below also exist
|
# Note that the hooks below also exist
|
||||||
# in the character object's typeclass. You
|
# in the character object's typeclass. You
|
||||||
# can often ignore these and rely on the
|
# can often ignore these and rely on the
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
"""
|
"""
|
||||||
This module implements the main Evennia server process, the core of
|
This module implements the main Evennia server process, the core of
|
||||||
the game engine. Only import this once!
|
the game engine. Don't import this module! If you need to access the
|
||||||
|
server processes from code, instead import sessionhandler.SESSIONS
|
||||||
|
and use its 'server' property.
|
||||||
|
|
||||||
This module should be started with the 'twistd' executable since it
|
This module should be started with the 'twistd' executable since it
|
||||||
sets up all the networking features. (this is done by
|
sets up all the networking features. (this is done by automatically
|
||||||
game/evennia.py).
|
by game/evennia.py).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
|
||||||
|
|
@ -145,9 +145,8 @@ class SessionBase(object):
|
||||||
and have to be done right after this function!
|
and have to be done right after this function!
|
||||||
"""
|
"""
|
||||||
if self.logged_in:
|
if self.logged_in:
|
||||||
character = self.get_character()
|
player = self.get_player()
|
||||||
if character:
|
uaccount = player.user
|
||||||
uaccount = character.player.user
|
|
||||||
uaccount.last_login = datetime.now()
|
uaccount.last_login = datetime.now()
|
||||||
uaccount.save()
|
uaccount.save()
|
||||||
self.at_disconnect()
|
self.at_disconnect()
|
||||||
|
|
@ -230,12 +229,14 @@ class SessionBase(object):
|
||||||
character = self.get_character()
|
character = self.get_character()
|
||||||
|
|
||||||
if character:
|
if character:
|
||||||
#print "loggedin _execute_cmd: '%s' __ %s" % (command_string, character)
|
|
||||||
# normal operation.
|
# normal operation.
|
||||||
character.execute_cmd(command_string)
|
character.execute_cmd(command_string)
|
||||||
else:
|
else:
|
||||||
#print "unloggedin _execute_cmd: '%s' __ %s" % (command_string, character)
|
if self.logged_in:
|
||||||
# we are not logged in yet; call cmdhandler directly
|
# there is no character, but we are logged in. Use player instead.
|
||||||
|
self.get_player().execute_cmd(command_string)
|
||||||
|
else:
|
||||||
|
# we are not logged in. Use special unlogged-in call.
|
||||||
cmdhandler.cmdhandler(self, command_string, unloggedin=True)
|
cmdhandler.cmdhandler(self, command_string, unloggedin=True)
|
||||||
self.update_session_counters()
|
self.update_session_counters()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,21 +136,18 @@ DATABASE_PORT = ''
|
||||||
###################################################
|
###################################################
|
||||||
|
|
||||||
# An alternate command parser module to use
|
# An alternate command parser module to use
|
||||||
# (if not set, uses 'src.commands.cmdparser')
|
COMMAND_PARSER = "src.commands.cmdparser.cmdparser"
|
||||||
ALTERNATE_PARSER = ""
|
|
||||||
# How many space-separated words a command name may have
|
# How many space-separated words a command name may have
|
||||||
# and still be identified as one single command
|
# and still be identified as one single command
|
||||||
# (e.g. 'push button' instead of 'pushbutton')
|
# (e.g. 'push button' instead of 'pushbutton')
|
||||||
COMMAND_MAXLEN = 3
|
COMMAND_MAXLEN = 3
|
||||||
# The handler that outputs errors when searching
|
# The handler that outputs errors when searching
|
||||||
# objects using object.search(). (If not set, uses
|
# objects using object.search().
|
||||||
# src.objects.object_search_funcs.handle_search_errors)
|
SEARCH_AT_RESULT = "src.commands.cmdparser.at_search_result"
|
||||||
ALTERNATE_OBJECT_SEARCH_ERROR_HANDLER = ""
|
|
||||||
# The parser used in order to separate multiple
|
# The parser used in order to separate multiple
|
||||||
# object matches (so you can separate between same-named
|
# object matches (so you can separate between same-named
|
||||||
# objects without using dbrefs). (If not set, uses
|
# objects without using dbrefs).
|
||||||
# src.objects.object_search_funcs.object_multimatch_parser).
|
SEARCH_AT_MULTIMATCH_INPUT = "src.commands.cmdparser.at_multimatch_input"
|
||||||
ALTERNATE_OBJECT_SEARCH_MULTIMATCH_PARSER = ""
|
|
||||||
# The module holding text strings for the connection screen.
|
# The module holding text strings for the connection screen.
|
||||||
# This module should contain one or more variables
|
# This module should contain one or more variables
|
||||||
# with strings defining the look of the screen.
|
# with strings defining the look of the screen.
|
||||||
|
|
@ -162,8 +159,10 @@ CONNECTION_SCREEN_MODULE = "game.gamesrc.world.connection_screens"
|
||||||
|
|
||||||
# Command set used before player has logged in
|
# Command set used before player has logged in
|
||||||
CMDSET_UNLOGGEDIN = "game.gamesrc.commands.basecmdset.UnloggedinCmdSet"
|
CMDSET_UNLOGGEDIN = "game.gamesrc.commands.basecmdset.UnloggedinCmdSet"
|
||||||
# Default set for logged in players (fallback)
|
# Default set for logged in player with characters (fallback)
|
||||||
CMDSET_DEFAULT = "game.gamesrc.commands.basecmdset.DefaultCmdSet"
|
CMDSET_DEFAULT = "game.gamesrc.commands.basecmdset.DefaultCmdSet"
|
||||||
|
# Command set for players without a character (ooc)
|
||||||
|
CMDSET_OOC = "game.gamesrc.commands.basecmdset.OOCCmdSet"
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# Default Object typeclasses
|
# Default Object typeclasses
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,87 @@ class Attribute(SharedMemoryModel):
|
||||||
return self.locks.check(accessing_obj, access_type=access_type, default=default)
|
return self.locks.check(accessing_obj, access_type=access_type, default=default)
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Nicks
|
||||||
|
#
|
||||||
|
#------------------------------------------------------------
|
||||||
|
|
||||||
|
class TypeNick(SharedMemoryModel):
|
||||||
|
"""
|
||||||
|
This model holds whichever alternate names this object
|
||||||
|
has for OTHER objects, but also for arbitrary strings,
|
||||||
|
channels, players etc. Setting a nick does not affect
|
||||||
|
the nicknamed object at all (as opposed to Aliases above),
|
||||||
|
and only this object will be able to refer to the nicknamed
|
||||||
|
object by the given nick.
|
||||||
|
|
||||||
|
The default nick types used by Evennia are:
|
||||||
|
inputline (default) - match against all input
|
||||||
|
player - match against player searches
|
||||||
|
obj - match against object searches
|
||||||
|
channel - used to store own names for channels
|
||||||
|
|
||||||
|
"""
|
||||||
|
db_nick = models.CharField(max_length=255, db_index=True) # the nick
|
||||||
|
db_real = models.TextField() # the aliased string
|
||||||
|
db_type = models.CharField(default="inputline", max_length=16, null=True, blank=True) # the type of nick
|
||||||
|
db_obj = None #models.ForeignKey("ObjectDB")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"Define Django meta options"
|
||||||
|
abstract = True
|
||||||
|
verbose_name = "Nickname"
|
||||||
|
verbose_name_plural = "Nicknames"
|
||||||
|
unique_together = ("db_nick", "db_type", "db_obj")
|
||||||
|
|
||||||
|
class TypeNickHandler(object):
|
||||||
|
"""
|
||||||
|
Handles nick access and setting. Accessed through ObjectDB.nicks
|
||||||
|
"""
|
||||||
|
|
||||||
|
NickClass = TypeNick
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
"Setup"
|
||||||
|
self.obj = obj
|
||||||
|
|
||||||
|
def add(self, nick, realname, nick_type="inputline"):
|
||||||
|
"We want to assign a new nick"
|
||||||
|
if not nick or not nick.strip():
|
||||||
|
return
|
||||||
|
nick = nick.strip()
|
||||||
|
real = realname.strip()
|
||||||
|
query = self.NickClass.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
|
||||||
|
if query.count():
|
||||||
|
old_nick = query[0]
|
||||||
|
old_nick.db_real = real
|
||||||
|
old_nick.save()
|
||||||
|
else:
|
||||||
|
new_nick = self.NickClass(db_nick=nick, db_real=real, db_type=nick_type, db_obj=self.obj)
|
||||||
|
new_nick.save()
|
||||||
|
def delete(self, nick, nick_type="inputline"):
|
||||||
|
"Removes a nick"
|
||||||
|
nick = nick.strip()
|
||||||
|
query = self.NickClass.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
|
||||||
|
if query.count():
|
||||||
|
# remove the found nick(s)
|
||||||
|
query.delete()
|
||||||
|
def get(self, nick=None, nick_type="inputline"):
|
||||||
|
if nick:
|
||||||
|
query = self.NickClass.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
|
||||||
|
query = query.values_list("db_real", flat=True)
|
||||||
|
if query.count():
|
||||||
|
return query[0]
|
||||||
|
else:
|
||||||
|
return nick
|
||||||
|
else:
|
||||||
|
return self.NickClass.objects.filter(db_obj=self.obj)
|
||||||
|
def has(self, nick, nick_type="inputline"):
|
||||||
|
"Returns true/false if this nick is defined or not"
|
||||||
|
return self.NickClass.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type).count()
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Typed Objects
|
# Typed Objects
|
||||||
|
|
@ -992,9 +1073,12 @@ class TypedObject(SharedMemoryModel):
|
||||||
|
|
||||||
def check_permstring(self, permstring):
|
def check_permstring(self, permstring):
|
||||||
"""
|
"""
|
||||||
This explicitly checks for we hold particular permission without involving
|
This explicitly checks if we hold particular permission without involving
|
||||||
any locks.
|
any locks.
|
||||||
"""
|
"""
|
||||||
|
if self.player and self.player.is_superuser:
|
||||||
|
return True
|
||||||
|
|
||||||
if not permstring:
|
if not permstring:
|
||||||
return False
|
return False
|
||||||
perm = permstring.lower()
|
perm = permstring.lower()
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,7 @@ def create_player(name, email, password,
|
||||||
new_player = PlayerDB(db_key=name, user=new_user)
|
new_player = PlayerDB(db_key=name, user=new_user)
|
||||||
new_player.save()
|
new_player.save()
|
||||||
|
|
||||||
|
new_player.basetype_setup() # setup the basic locks and cmdset
|
||||||
# call hook method (may override default permissions)
|
# call hook method (may override default permissions)
|
||||||
new_player.at_player_creation()
|
new_player.at_player_creation()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,8 +173,8 @@ def reset_loop():
|
||||||
[m.locks.reset() for m in Msg.objects.all()]
|
[m.locks.reset() for m in Msg.objects.all()]
|
||||||
[c.locks.reset() for c in Channel.objects.all()]
|
[c.locks.reset() for c in Channel.objects.all()]
|
||||||
[s.locks.reset() for s in ScriptDB.objects.all()]
|
[s.locks.reset() for s in ScriptDB.objects.all()]
|
||||||
[p.locks.reset() for p in PlayerDB.objects.all()]
|
|
||||||
[(o.typeclass(o), o.cmdset.reset(), o.locks.reset()) for o in ObjectDB.get_all_cached_instances()]
|
[(o.typeclass(o), o.cmdset.reset(), o.locks.reset()) for o in ObjectDB.get_all_cached_instances()]
|
||||||
|
[(p.typeclass(p), p.cmdset.reset(), p.locks.reset()) for p in PlayerDB.get_all_cached_instances()]
|
||||||
|
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
cemit_info(" ... Loop finished in %g seconds." % (t2-t1))
|
cemit_info(" ... Loop finished in %g seconds." % (t2-t1))
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,15 @@ Example: To reach the search method 'get_object_with_user'
|
||||||
|
|
||||||
# Import the manager methods to be wrapped
|
# Import the manager methods to be wrapped
|
||||||
|
|
||||||
from src.objects.models import ObjectDB
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from src.players.models import PlayerDB
|
|
||||||
from src.scripts.models import ScriptDB
|
# import objects this way to avoid circular import problems
|
||||||
from src.comms.models import Msg, Channel
|
ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
|
||||||
from src.help.models import HelpEntry
|
PlayerDB = ContentType.objects.get(app_label="players", model="playerdb").model_class()
|
||||||
|
ScriptDB = ContentType.objects.get(app_label="scripts", model="scriptdb").model_class()
|
||||||
|
Msg = ContentType.objects.get(app_label="comms", model="msg").model_class()
|
||||||
|
Channel = ContentType.objects.get(app_label="comms", model="channel").model_class()
|
||||||
|
HelpEntry = ContentType.objects.get(app_label="help", model="helpentry").model_class()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Search objects as a character
|
# Search objects as a character
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,5 @@ class EvenniaTestSuiteRunner(DjangoTestSuiteRunner):
|
||||||
test_labels = [applabel.rsplit('.', 1)[1] for applabel in settings.INSTALLED_APPS
|
test_labels = [applabel.rsplit('.', 1)[1] for applabel in settings.INSTALLED_APPS
|
||||||
if (applabel.startswith('src.') or applabel.startswith('game.'))]
|
if (applabel.startswith('src.') or applabel.startswith('game.'))]
|
||||||
return super(EvenniaTestSuiteRunner, self).build_suite(test_labels, extra_tests=extra_tests, **kwargs)
|
return super(EvenniaTestSuiteRunner, self).build_suite(test_labels, extra_tests=extra_tests, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,14 +235,28 @@ def dbref(dbref):
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
return dbref
|
return dbref
|
||||||
|
return None
|
||||||
|
|
||||||
def to_unicode(obj, encoding='utf-8'):
|
def to_unicode(obj, encoding='utf-8', force_string=False):
|
||||||
"""
|
"""
|
||||||
This decodes a suitable object to
|
This decodes a suitable object to the unicode format. Note that
|
||||||
the unicode format. Note that one
|
one needs to encode it back to utf-8 before writing to disk or
|
||||||
needs to encode it back to utf-8
|
printing. Note that non-string objects are let through without
|
||||||
before writing to disk or printing.
|
conversion - this is important for e.g. Attributes. Use
|
||||||
|
force_string to enforce conversion of objects to string. .
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if force_string and not isinstance(obj, basestring):
|
||||||
|
# some sort of other object. Try to
|
||||||
|
# convert it to a string representation.
|
||||||
|
if hasattr(obj, '__str__'):
|
||||||
|
obj = obj.__str__()
|
||||||
|
elif hasattr(obj, '__unicode__'):
|
||||||
|
obj = obj.__unicode__()
|
||||||
|
else:
|
||||||
|
# last resort
|
||||||
|
obj = str(obj)
|
||||||
|
|
||||||
if isinstance(obj, basestring) and not isinstance(obj, unicode):
|
if isinstance(obj, basestring) and not isinstance(obj, unicode):
|
||||||
try:
|
try:
|
||||||
obj = unicode(obj, encoding)
|
obj = unicode(obj, encoding)
|
||||||
|
|
@ -257,11 +271,26 @@ def to_unicode(obj, encoding='utf-8'):
|
||||||
raise Exception("Error: '%s' contains invalid character(s) not in %s." % (obj, encoding))
|
raise Exception("Error: '%s' contains invalid character(s) not in %s." % (obj, encoding))
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def to_str(obj, encoding='utf-8'):
|
def to_str(obj, encoding='utf-8', force_string=False):
|
||||||
"""
|
"""
|
||||||
This encodes a unicode string back to byte-representation,
|
This encodes a unicode string back to byte-representation,
|
||||||
for printing, writing to disk etc.
|
for printing, writing to disk etc. Note that non-string
|
||||||
|
objects are let through without modification - this is
|
||||||
|
required e.g. for Attributes. Use force_string to force
|
||||||
|
conversion of objects to strings.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if force_string and not isinstance(obj, basestring):
|
||||||
|
# some sort of other object. Try to
|
||||||
|
# convert it to a string representation.
|
||||||
|
if hasattr(obj, '__str__'):
|
||||||
|
obj = obj.__str__()
|
||||||
|
elif hasattr(obj, '__unicode__'):
|
||||||
|
obj = obj.__unicode__()
|
||||||
|
else:
|
||||||
|
# last resort
|
||||||
|
obj = str(obj)
|
||||||
|
|
||||||
if isinstance(obj, basestring) and isinstance(obj, unicode):
|
if isinstance(obj, basestring) and isinstance(obj, unicode):
|
||||||
try:
|
try:
|
||||||
obj = obj.encode(encoding)
|
obj = obj.encode(encoding)
|
||||||
|
|
@ -321,7 +350,7 @@ def inherits_from(obj, parent):
|
||||||
Takes an object and tries to determine if it inherits at any distance
|
Takes an object and tries to determine if it inherits at any distance
|
||||||
from parent. What differs this function from e.g. isinstance()
|
from parent. What differs this function from e.g. isinstance()
|
||||||
is that obj may be both an instance and a class, and parent
|
is that obj may be both an instance and a class, and parent
|
||||||
may be an instance, a class, or the python path to a class (counting
|
< may be an instance, a class, or the python path to a class (counting
|
||||||
from the evennia root directory).
|
from the evennia root directory).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -480,10 +509,11 @@ def has_parent(basepath, obj):
|
||||||
# instance. Not sure if one should defend against this.
|
# instance. Not sure if one should defend against this.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def mod_import(mod_path):
|
def mod_import(mod_path, propname=None):
|
||||||
"""
|
"""
|
||||||
Takes filename of a module, converts it to a python path
|
Takes filename of a module, converts it to a python path
|
||||||
and imports it.
|
and imports it. If property is given, return the named
|
||||||
|
property from this module instead of the module itself.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def log_trace(errmsg=None):
|
def log_trace(errmsg=None):
|
||||||
|
|
@ -494,6 +524,7 @@ def mod_import(mod_path):
|
||||||
"""
|
"""
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
|
print errmsg
|
||||||
|
|
||||||
tracestring = format_exc()
|
tracestring = format_exc()
|
||||||
if tracestring:
|
if tracestring:
|
||||||
|
|
@ -507,6 +538,13 @@ def mod_import(mod_path):
|
||||||
for line in errmsg.splitlines():
|
for line in errmsg.splitlines():
|
||||||
log.msg('[EE] %s' % line)
|
log.msg('[EE] %s' % line)
|
||||||
|
|
||||||
|
# first try to import as a python path
|
||||||
|
try:
|
||||||
|
mod = __import__(mod_path, fromlist=["None"])
|
||||||
|
except ImportError:
|
||||||
|
|
||||||
|
# try absolute path import instead
|
||||||
|
|
||||||
if not os.path.isabs(mod_path):
|
if not os.path.isabs(mod_path):
|
||||||
mod_path = os.path.abspath(mod_path)
|
mod_path = os.path.abspath(mod_path)
|
||||||
path, filename = mod_path.rsplit(os.path.sep, 1)
|
path, filename = mod_path.rsplit(os.path.sep, 1)
|
||||||
|
|
@ -524,6 +562,15 @@ def mod_import(mod_path):
|
||||||
mod = None
|
mod = None
|
||||||
# we have to close the file handle manually
|
# we have to close the file handle manually
|
||||||
result[0].close()
|
result[0].close()
|
||||||
|
|
||||||
|
if mod and propname:
|
||||||
|
# we have a module, extract the sought property from it.
|
||||||
|
try:
|
||||||
|
mod_prop = mod.__dict__[to_str(propname)]
|
||||||
|
except KeyError:
|
||||||
|
log_trace("Could not import property '%s' from module %s." % (propname, mod_path))
|
||||||
|
return None
|
||||||
|
return mod_prop
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
def string_from_module(modpath, variable=None):
|
def string_from_module(modpath, variable=None):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue