mirror of
https://github.com/evennia/evennia.git
synced 2026-03-28 02:36:32 +01:00
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.default import cmdset_default, cmdset_unloggedin
|
||||
from src.commands.default import cmdset_default, cmdset_unloggedin, cmdset_ooc
|
||||
|
||||
from game.gamesrc.commands.basecommand import Command
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ class DefaultCmdSet(cmdset_default.DefaultCmdSet):
|
|||
Populates the cmdset
|
||||
"""
|
||||
super(DefaultCmdSet, self).at_cmdset_creation()
|
||||
|
||||
|
||||
#
|
||||
# any commands you add below will overload the default ones.
|
||||
#
|
||||
|
|
@ -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):
|
||||
"""
|
||||
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):
|
||||
|
||||
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.
|
||||
Almost all object customizations go here.
|
||||
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.commands.cmdsethandler import import_cmdset
|
||||
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.
|
||||
# You have to restart the server for this to take effect.
|
||||
try:
|
||||
CMDPARSER = __import__(settings.ALTERNATE_PARSER, fromlist=[True]).cmdparser
|
||||
except Exception:
|
||||
from src.commands.cmdparser import cmdparser as CMDPARSER
|
||||
COMMAND_PARSER = utils.mod_import(*settings.COMMAND_PARSER.rsplit('.', 1))
|
||||
|
||||
# There are a few system-hardcoded command names. These
|
||||
# allow for custom behaviour when the command handler hits
|
||||
|
|
@ -101,13 +98,21 @@ def get_and_merge_cmdsets(caller):
|
|||
exit_cmdset = 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:
|
||||
# Make cmdsets out of all valid channels
|
||||
channel_cmdset = CHANNELHANDLER.get_cmdset(caller)
|
||||
if not caller_cmdset.no_exits:
|
||||
# Make cmdsets out of all valid exits in the room
|
||||
exit_cmdset = EXITHANDLER.get_cmdset(caller)
|
||||
location = caller.location
|
||||
location = None
|
||||
if hasattr(caller, "location"):
|
||||
location = caller.location
|
||||
if location and not caller_cmdset.no_objs:
|
||||
# Gather all cmdsets stored on objects in the room and
|
||||
# also in the caller's inventory
|
||||
|
|
@ -138,6 +143,12 @@ def get_and_merge_cmdsets(caller):
|
|||
cmdset = channel_cmdset + cmdset
|
||||
except TypeError:
|
||||
pass
|
||||
# finally merge on the player cmdset. This should have a low priority
|
||||
try:
|
||||
cmdset = player_cmdset + cmdset
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
return cmdset
|
||||
|
||||
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)
|
||||
|
||||
# Parse the input string into command candidates
|
||||
cmd_candidates = CMDPARSER(raw_string)
|
||||
cmd_candidates = COMMAND_PARSER(raw_string)
|
||||
|
||||
#string ="Command candidates"
|
||||
#for cand in cmd_candidates:
|
||||
|
|
|
|||
|
|
@ -174,3 +174,128 @@ def cmdparser(raw_string):
|
|||
wordlist = raw_string.split(" ")
|
||||
candidates.extend(produce_candidates(nr_candidates, wordlist))
|
||||
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
|
||||
from src.utils.utils import inherits_from, is_iter
|
||||
|
||||
RECURSIVE_PROTECTION = False
|
||||
|
||||
class CmdSetMeta(type):
|
||||
"""
|
||||
|
|
@ -204,16 +207,40 @@ class CmdSet(object):
|
|||
|
||||
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,
|
||||
it will replace the old one (no priority checking etc
|
||||
at this point; this is often used to overload
|
||||
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'):
|
||||
cmd.obj = self.cmdsetobj
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ class CmdSetHandler(object):
|
|||
string += "\n"
|
||||
merged = True
|
||||
|
||||
# Display the currently active cmdset
|
||||
# Display the currently active cmdset, limited by self.obj's permissions
|
||||
mergetype = self.mergetype_stack[-1]
|
||||
if mergetype != self.current.mergetype:
|
||||
merged_on = self.cmdset_stack[-2].key
|
||||
|
|
@ -187,7 +187,8 @@ class CmdSetHandler(object):
|
|||
if merged:
|
||||
string += " <Merged (%s)>: %s" % (mergetype, self.current)
|
||||
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()
|
||||
|
||||
def update(self, init_mode=False):
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class CmdBoot(MuxCommand):
|
|||
break
|
||||
else:
|
||||
# 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:
|
||||
return
|
||||
if pobj.character.has_player:
|
||||
|
|
@ -118,6 +118,9 @@ class CmdDelPlayer(MuxCommand):
|
|||
caller = self.caller
|
||||
args = self.args
|
||||
|
||||
if hasattr(caller, 'player'):
|
||||
caller = caller.player
|
||||
|
||||
if not args:
|
||||
caller.msg("Usage: @delplayer[/delobj] <player/user name or #id> [: reason]")
|
||||
return
|
||||
|
|
@ -128,7 +131,7 @@ class CmdDelPlayer(MuxCommand):
|
|||
|
||||
# We use player_search since we want to be sure to find also players
|
||||
# that lack characters.
|
||||
players = caller.search("*%s" % args)
|
||||
players = caller.search("*%s" % args, player=True)
|
||||
if not players:
|
||||
try:
|
||||
players = PlayerDB.objects.filter(id=args)
|
||||
|
|
@ -304,7 +307,7 @@ class CmdNewPassword(MuxCommand):
|
|||
return
|
||||
|
||||
# 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:
|
||||
return
|
||||
player.user.set_password(self.rhs)
|
||||
|
|
@ -320,12 +323,14 @@ class CmdPerm(MuxCommand):
|
|||
|
||||
Usage:
|
||||
@perm[/switch] <object> [= <permission>[,<permission>,...]]
|
||||
@perm[/switch] *<player> [= <permission>[,<permission>,...]]
|
||||
|
||||
Switches:
|
||||
del : delete the given permission from <object>.
|
||||
|
||||
This command sets/clears individual permission strings on an object.
|
||||
If no permission is given, list all permissions on <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
|
||||
or player. If no permission is given, list all permissions on <object>.
|
||||
"""
|
||||
key = "@perm"
|
||||
aliases = "@setperm"
|
||||
|
|
@ -340,17 +345,18 @@ class CmdPerm(MuxCommand):
|
|||
lhs, rhs = self.lhs, self.rhs
|
||||
|
||||
if not self.args:
|
||||
string = "Usage: @perm[/switch] object [ = permission, permission, ...]\n"
|
||||
string = "Usage: @perm[/switch] object [ = permission, permission, ...]"
|
||||
caller.msg(string)
|
||||
return
|
||||
|
||||
# locate the object
|
||||
obj = caller.search(lhs, global_search=True)
|
||||
|
||||
playermode = 'player' in self.switches or lhs.startswith('*')
|
||||
|
||||
# locate the object
|
||||
obj = caller.search(lhs, global_search=True, player=playermode)
|
||||
if not obj:
|
||||
return
|
||||
|
||||
if not rhs:
|
||||
|
||||
if not obj.access(caller, 'examine'):
|
||||
caller.msg("You are not allowed to examine this object.")
|
||||
return
|
||||
|
|
@ -396,12 +402,10 @@ class CmdPerm(MuxCommand):
|
|||
|
||||
|
||||
for perm in self.rhslist:
|
||||
|
||||
perm = perm.lower()
|
||||
|
||||
# don't allow to set a permission higher in the hierarchy than the one the
|
||||
# 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.")
|
||||
return
|
||||
|
||||
|
|
@ -416,45 +420,6 @@ class CmdPerm(MuxCommand):
|
|||
if tstring:
|
||||
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):
|
||||
"""
|
||||
@wall
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Building and world design commands
|
|||
|
||||
from django.conf import settings
|
||||
from src.objects.models import ObjectDB, ObjAttribute
|
||||
from src.players.models import PlayerAttribute
|
||||
from src.utils import create, utils, debug
|
||||
from src.commands.default.muxcommand import MuxCommand
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ class CmdSetObjAlias(MuxCommand):
|
|||
old_aliases = obj.aliases
|
||||
if 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:
|
||||
caller.msg("No aliases to clear.")
|
||||
return
|
||||
|
|
@ -1389,16 +1390,25 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
Usage:
|
||||
examine [<object>[/attrname]]
|
||||
examine [*<player>[/attrname]]
|
||||
|
||||
Switch:
|
||||
player - examine a Player (same as adding *)
|
||||
|
||||
The examine command shows detailed game info about an
|
||||
object and optionally a specific attribute on it.
|
||||
If object is not specified, the current location is examined.
|
||||
|
||||
Append a * before the search string to examine a player.
|
||||
|
||||
"""
|
||||
key = "@examine"
|
||||
aliases = ["@ex","ex", "exam", "examine"]
|
||||
locks = "cmd:perm(examine) or perm(Builders)"
|
||||
help_category = "Building"
|
||||
|
||||
player_mode = False
|
||||
|
||||
def format_attributes(self, obj, attrname=None, crop=True):
|
||||
"""
|
||||
Helper function that returns info about attributes and/or
|
||||
|
|
@ -1411,7 +1421,10 @@ class CmdExamine(ObjManipCommand):
|
|||
except Exception:
|
||||
ndb_attr = None
|
||||
else:
|
||||
db_attr = [(attr.key, attr.value) for attr in ObjAttribute.objects.filter(db_obj=obj)]
|
||||
if player_mode:
|
||||
db_attr = [(attr.key, attr.value) for attr in PlayerAttribute.objects.filter(db_obj=obj)]
|
||||
else:
|
||||
db_attr = [(attr.key, attr.value) for attr in ObjAttribute.objects.filter(db_obj=obj)]
|
||||
try:
|
||||
ndb_attr = [(aname, avalue) for aname, avalue in obj.ndb.__dict__.items()]
|
||||
except Exception:
|
||||
|
|
@ -1439,24 +1452,25 @@ class CmdExamine(ObjManipCommand):
|
|||
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)
|
||||
else:
|
||||
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))
|
||||
if obj.has_player:
|
||||
if hasattr(obj, "has_player") and obj.has_player:
|
||||
string += "\n{wPlayer{n: {c%s{n" % obj.player.name
|
||||
perms = obj.player.permissions
|
||||
if obj.player.is_superuser:
|
||||
perms = ["<Superuser>"]
|
||||
elif not perms:
|
||||
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{wLocation{n: %s" % obj.location
|
||||
if obj.destination:
|
||||
|
||||
if hasattr(obj, "location"):
|
||||
string += "\n{wLocation{n: %s" % obj.location
|
||||
if hasattr(obj, "destination") and obj.destination:
|
||||
string += "\n{wDestination{n: %s" % obj.destination
|
||||
perms = obj.permissions
|
||||
if perms:
|
||||
|
|
@ -1467,8 +1481,8 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
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")])
|
||||
string += "\n{wCurrent Cmdset (before permission checks){n:\n %s" % cmdsetstr
|
||||
if obj.scripts.all():
|
||||
string += "\n{wCurrent Cmdset (including permission checks){n:\n %s" % cmdsetstr
|
||||
if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all():
|
||||
string += "\n{wScripts{n:\n %s" % obj.scripts
|
||||
# add the attributes
|
||||
string += self.format_attributes(obj)
|
||||
|
|
@ -1476,21 +1490,21 @@ class CmdExamine(ObjManipCommand):
|
|||
exits = []
|
||||
pobjs = []
|
||||
things = []
|
||||
for content in obj.contents:
|
||||
if content.destination:
|
||||
# an exit
|
||||
exits.append(content)
|
||||
elif content.player:
|
||||
pobjs.append(content)
|
||||
else:
|
||||
things.append(content)
|
||||
if exits:
|
||||
string += "\n{wExits{n: " + ", ".join([exit.name for exit in exits])
|
||||
if pobjs:
|
||||
string += "\n{wCharacters{n: " + ", ".join(["{c%s{n" % pobj.name for pobj in pobjs])
|
||||
if things:
|
||||
string += "\n{wContents{n: " + ", ".join([cont.name for cont in obj.contents
|
||||
if cont not in exits and cont not in pobjs])
|
||||
if hasattr(obj, "contents"):
|
||||
for content in obj.contents:
|
||||
if content.destination:
|
||||
exits.append(content)
|
||||
elif content.player:
|
||||
pobjs.append(content)
|
||||
else:
|
||||
things.append(content)
|
||||
if exits:
|
||||
string += "\n{wExits{n: " + ", ".join([exit.name for exit in exits])
|
||||
if pobjs:
|
||||
string += "\n{wCharacters{n: " + ", ".join(["{c%s{n" % pobj.name for pobj in pobjs])
|
||||
if things:
|
||||
string += "\n{wContents{n: " + ", ".join([cont.name for cont in obj.contents
|
||||
if cont not in exits and cont not in pobjs])
|
||||
#output info
|
||||
return "-"*78 + '\n' + string.strip() + "\n" + '-'*78
|
||||
|
||||
|
|
@ -1506,36 +1520,35 @@ class CmdExamine(ObjManipCommand):
|
|||
caller.execute_cmd('look %s' % obj.name)
|
||||
return
|
||||
string = self.format_output(obj)
|
||||
|
||||
else:
|
||||
# we have given a specific target object
|
||||
|
||||
string = ""
|
||||
|
||||
for objdef in self.lhs_objattr:
|
||||
|
||||
obj_name = objdef['name']
|
||||
obj_attrs = objdef['attrs']
|
||||
|
||||
obj = caller.search(obj_name)
|
||||
if not obj:
|
||||
continue
|
||||
|
||||
if not obj.access(caller, 'examine'):
|
||||
#If we don't have special info access, just look at the object instead.
|
||||
caller.execute_cmd('look %s' % obj_name)
|
||||
continue
|
||||
|
||||
if obj_attrs:
|
||||
for attrname in obj_attrs:
|
||||
# we are only interested in specific attributes
|
||||
string += self.format_attributes(obj, attrname, crop=False)
|
||||
else:
|
||||
string += self.format_output(obj)
|
||||
string = string.strip()
|
||||
# Send it all
|
||||
if string:
|
||||
caller.msg(string.strip())
|
||||
return
|
||||
|
||||
# we have given a specific target object
|
||||
string = ""
|
||||
for objdef in self.lhs_objattr:
|
||||
|
||||
obj_name = objdef['name']
|
||||
obj_attrs = objdef['attrs']
|
||||
|
||||
global player_mode
|
||||
player_mode = "player" in self.switches or obj_name.startswith('*')
|
||||
|
||||
obj = caller.search(obj_name, player=player_mode)
|
||||
if not obj:
|
||||
continue
|
||||
|
||||
if not obj.access(caller, 'examine'):
|
||||
#If we don't have special info access, just look at the object instead.
|
||||
caller.execute_cmd('look %s' % obj_name)
|
||||
continue
|
||||
|
||||
if obj_attrs:
|
||||
for attrname in obj_attrs:
|
||||
# we are only interested in specific attributes
|
||||
string += self.format_attributes(obj, attrname, crop=False)
|
||||
else:
|
||||
string += self.format_output(obj)
|
||||
caller.msg(string.strip())
|
||||
|
||||
|
||||
class CmdFind(MuxCommand):
|
||||
|
|
|
|||
|
|
@ -18,17 +18,14 @@ class DefaultCmdSet(CmdSet):
|
|||
# The general commands
|
||||
self.add(general.CmdLook())
|
||||
self.add(general.CmdHome())
|
||||
self.add(general.CmdPassword())
|
||||
self.add(general.CmdWho())
|
||||
self.add(general.CmdInventory())
|
||||
self.add(general.CmdQuit())
|
||||
self.add(general.CmdPose())
|
||||
self.add(general.CmdNick())
|
||||
self.add(general.CmdGet())
|
||||
self.add(general.CmdDrop())
|
||||
self.add(general.CmdWho())
|
||||
self.add(general.CmdSay())
|
||||
self.add(general.CmdAccess())
|
||||
self.add(general.CmdEncoding())
|
||||
|
||||
# The help system
|
||||
self.add(help.CmdHelp())
|
||||
|
|
@ -52,7 +49,6 @@ class DefaultCmdSet(CmdSet):
|
|||
self.add(admin.CmdEmit())
|
||||
self.add(admin.CmdNewPassword())
|
||||
self.add(admin.CmdPerm())
|
||||
self.add(admin.CmdPuppet())
|
||||
self.add(admin.CmdWall())
|
||||
|
||||
# Building and world manipulation
|
||||
|
|
@ -79,24 +75,6 @@ class DefaultCmdSet(CmdSet):
|
|||
self.add(building.CmdLock())
|
||||
self.add(building.CmdScript())
|
||||
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
|
||||
self.add(batchprocess.CmdBatchCommands())
|
||||
|
|
|
|||
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 src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection
|
||||
|
|
@ -29,6 +35,25 @@ def find_channel(caller, channelname, silent=False, noaliases=False):
|
|||
caller.msg("Multiple channels match (be more specific): \n%s" % matches)
|
||||
return None
|
||||
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):
|
||||
"""
|
||||
|
|
@ -46,14 +71,14 @@ class CmdAddCom(MuxCommand):
|
|||
key = "addcom"
|
||||
aliases = ["aliaschan","chanalias"]
|
||||
help_category = "Comms"
|
||||
locks = "cmd:not perm(channel_banned)"
|
||||
locks = "cmd:not pperm(channel_banned)"
|
||||
|
||||
def func(self):
|
||||
"Implement the command"
|
||||
|
||||
caller = self.caller
|
||||
args = self.args
|
||||
player = caller.player
|
||||
player = caller
|
||||
|
||||
if not args:
|
||||
caller.msg("Usage: addcom [alias =] channelname.")
|
||||
|
|
@ -120,7 +145,7 @@ class CmdDelCom(MuxCommand):
|
|||
"Implementing the command. "
|
||||
|
||||
caller = self.caller
|
||||
player = caller.player
|
||||
player = caller
|
||||
|
||||
if not self.args:
|
||||
caller.msg("Usage: delcom <alias or channel>")
|
||||
|
|
@ -169,7 +194,7 @@ class CmdAllCom(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "allcom"
|
||||
locks = "cmd: not perm(channel_banned)"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -189,7 +214,7 @@ class CmdAllCom(MuxCommand):
|
|||
caller.execute_cmd("addcom %s" % channel.key)
|
||||
elif args == "off":
|
||||
#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:
|
||||
caller.execute_cmd("delcom %s" % channel.key)
|
||||
elif args == "destroy":
|
||||
|
|
@ -230,7 +255,7 @@ class CmdChannels(MuxCommand):
|
|||
key = "@channels"
|
||||
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
|
||||
help_category = "Comms"
|
||||
locks = "cmd: not perm(channel_banned)"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
|
||||
def func(self):
|
||||
"Implement function"
|
||||
|
|
@ -243,7 +268,7 @@ class CmdChannels(MuxCommand):
|
|||
caller.msg("No channels available.")
|
||||
return
|
||||
# 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":
|
||||
|
||||
|
|
@ -298,7 +323,7 @@ class CmdCdestroy(MuxCommand):
|
|||
|
||||
key = "@cdestroy"
|
||||
help_category = "Comms"
|
||||
locks = "cmd: not perm(channel_banned)"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
|
||||
def func(self):
|
||||
"Destroy objects cleanly."
|
||||
|
|
@ -337,7 +362,7 @@ class CmdCBoot(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "@cboot"
|
||||
locks = "cmd: not perm(channel_banned)"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -352,12 +377,12 @@ class CmdCBoot(MuxCommand):
|
|||
if not channel:
|
||||
return
|
||||
reason = ""
|
||||
player = None
|
||||
if ":" in self.rhs:
|
||||
playername, reason = self.rhs.rsplit(":", 1)
|
||||
player = self.caller.search("*%s" % playername.lstrip('*'))
|
||||
if not player:
|
||||
player = self.caller.search("*%s" % self.rhs.lstrip('*'))
|
||||
searchstring = playername.lstrip('*')
|
||||
else:
|
||||
searchstring = self.rhs.lstrip('*')
|
||||
player = self.caller.search(searchstring, player=True)
|
||||
if not player:
|
||||
return
|
||||
if reason:
|
||||
|
|
@ -400,7 +425,7 @@ class CmdCemit(MuxCommand):
|
|||
|
||||
key = "@cemit"
|
||||
aliases = ["@cmsg"]
|
||||
locks = "cmd: not perm(channel_banned)"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -437,7 +462,7 @@ class CmdCWho(MuxCommand):
|
|||
List who is connected to a given channel you have access to.
|
||||
"""
|
||||
key = "@cwho"
|
||||
locks = "cmd: not perm(channel_banned)"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -475,7 +500,7 @@ class CmdChannelCreate(MuxCommand):
|
|||
|
||||
key = "@ccreate"
|
||||
aliases = "channelcreate"
|
||||
locks = "cmd:not perm(channel_banned)"
|
||||
locks = "cmd:not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -522,7 +547,7 @@ class CmdCset(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "@cset"
|
||||
locks = "cmd:not perm(channel_banned)"
|
||||
locks = "cmd:not pperm(channel_banned)"
|
||||
aliases = ["@cclock"]
|
||||
help_category = "Comms"
|
||||
|
||||
|
|
@ -568,7 +593,7 @@ class CmdCdesc(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "@cdesc"
|
||||
locks = "cmd:not perm(channel_banned)"
|
||||
locks = "cmd:not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -611,7 +636,7 @@ class CmdPage(MuxCommand):
|
|||
|
||||
key = "page"
|
||||
aliases = ['tell']
|
||||
locks = "cmd:not perm(page_banned)"
|
||||
locks = "cmd:not pperm(page_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -619,7 +644,7 @@ class CmdPage(MuxCommand):
|
|||
"Implement function using the Msg methods"
|
||||
|
||||
caller = self.caller
|
||||
player = caller.player
|
||||
player = caller
|
||||
|
||||
# get the messages we've sent
|
||||
messages_we_sent = list(Msg.objects.get_messages_by_sender(player))
|
||||
|
|
@ -751,7 +776,7 @@ class CmdIRC2Chan(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "@irc2chan"
|
||||
locks = "cmd:serversetting(IRC_ENABLED) and perm(Immortals)"
|
||||
locks = "cmd:serversetting(IRC_ENABLED) and pperm(Immortals)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -840,7 +865,7 @@ class CmdIMC2Chan(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "@imc2chan"
|
||||
locks = "cmd:serversetting(IMC2_ENABLED) and perm(Immortals)"
|
||||
locks = "cmd:serversetting(IMC2_ENABLED) and pperm(Immortals)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -923,7 +948,7 @@ class CmdIMCInfo(MuxCommand):
|
|||
|
||||
key = "@imcinfo"
|
||||
aliases = ["@imcchanlist", "@imclist", "@imcwhois"]
|
||||
locks = "cmd: serversetting(IMC2_ENABLED) and perm(Wizards)"
|
||||
locks = "cmd: serversetting(IMC2_ENABLED) and pperm(Wizards)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -982,7 +1007,7 @@ class CmdIMCInfo(MuxCommand):
|
|||
return
|
||||
from src.comms.imc2 import IMC2_CLIENT
|
||||
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":
|
||||
# show channels
|
||||
|
|
@ -1051,6 +1076,6 @@ class CmdIMCTell(MuxCommand):
|
|||
data = {"target":target, "destination":destination}
|
||||
|
||||
# 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))
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ now.
|
|||
import time
|
||||
from django.conf import settings
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
from src.objects.models import HANDLE_SEARCH_ERRORS
|
||||
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
|
||||
|
||||
AT_SEARCH_RESULT = utils.mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS
|
||||
|
||||
class CmdHome(MuxCommand):
|
||||
"""
|
||||
home
|
||||
|
|
@ -45,7 +47,7 @@ class CmdLook(MuxCommand):
|
|||
Observes your location or objects in your vicinity.
|
||||
"""
|
||||
key = "look"
|
||||
aliases = ["l"]
|
||||
aliases = ["l", "ls"]
|
||||
locks = "cmd:all()"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -53,18 +55,19 @@ class CmdLook(MuxCommand):
|
|||
Handle the looking.
|
||||
"""
|
||||
caller = self.caller
|
||||
args = self.args # caller.msg(inp)
|
||||
args = self.args
|
||||
|
||||
if args:
|
||||
# Use search to handle duplicate/nonexistant results.
|
||||
looking_at_obj = caller.search(args, use_nicks=True)
|
||||
if not looking_at_obj:
|
||||
return
|
||||
return
|
||||
else:
|
||||
looking_at_obj = caller.location
|
||||
if not looking_at_obj:
|
||||
caller.msg("Location: None")
|
||||
caller.msg("You have no location to look at!")
|
||||
return
|
||||
|
||||
if not hasattr(looking_at_obj, 'return_appearance'):
|
||||
# this is likely due to us having a player instead
|
||||
looking_at_obj = looking_at_obj.character
|
||||
|
|
@ -89,6 +92,8 @@ class CmdPassword(MuxCommand):
|
|||
"hook function."
|
||||
|
||||
caller = self.caller
|
||||
if hasattr(caller, "player"):
|
||||
caller = caller.player
|
||||
|
||||
if not self.rhs:
|
||||
caller.msg("Usage: @password <oldpass> = <newpass>")
|
||||
|
|
@ -96,7 +101,7 @@ class CmdPassword(MuxCommand):
|
|||
oldpass = self.lhslist[0] # this is already stripped by parse()
|
||||
newpass = self.rhslist[0] # ''
|
||||
try:
|
||||
uaccount = caller.player.user
|
||||
uaccount = caller.user
|
||||
except AttributeError:
|
||||
caller.msg("This is only applicable for players.")
|
||||
return
|
||||
|
|
@ -309,7 +314,7 @@ class CmdDrop(MuxCommand):
|
|||
# those in our inventory.
|
||||
results = [obj for obj in results if obj in caller.contents]
|
||||
# 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:
|
||||
return
|
||||
|
||||
|
|
@ -348,13 +353,13 @@ class CmdWho(MuxCommand):
|
|||
who
|
||||
doing
|
||||
|
||||
Shows who is currently online. Doing is an
|
||||
alias that limits info also for those with
|
||||
all permissions.
|
||||
Shows who is currently online. Doing is an alias that limits info
|
||||
also for those with all permissions.
|
||||
"""
|
||||
|
||||
key = "who"
|
||||
aliases = "doing"
|
||||
locks = "cmd:all()"
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
|
|
@ -518,17 +523,20 @@ class CmdEncoding(MuxCommand):
|
|||
Sets the encoding.
|
||||
"""
|
||||
caller = self.caller
|
||||
if hasattr(caller, 'player'):
|
||||
caller = caller.player
|
||||
|
||||
if 'clear' in self.switches:
|
||||
# remove customization
|
||||
old_encoding = caller.player.db.encoding
|
||||
old_encoding = caller.db.encoding
|
||||
if old_encoding:
|
||||
string = "Your custom text encoding ('%s') was cleared." % old_encoding
|
||||
else:
|
||||
string = "No custom encoding was set."
|
||||
del caller.player.db.encoding
|
||||
del caller.db.encoding
|
||||
elif not self.args:
|
||||
# just list the encodings supported
|
||||
pencoding = caller.player.db.encoding
|
||||
pencoding = caller.db.encoding
|
||||
string = ""
|
||||
if 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."
|
||||
else:
|
||||
# change encoding
|
||||
old_encoding = caller.player.db.encoding
|
||||
old_encoding = caller.db.encoding
|
||||
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)
|
||||
caller.msg(string.strip())
|
||||
|
||||
|
|
@ -579,3 +587,141 @@ class CmdAccess(MuxCommand):
|
|||
if hasattr(caller, 'player'):
|
||||
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
|
||||
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("@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
|
||||
# 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
|
||||
|
||||
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()
|
||||
|
||||
character = player.character
|
||||
if character:
|
||||
# this player has a character. Check if it's the
|
||||
# first time *this character* logs in
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
# run character login hook
|
||||
character.at_pre_login()
|
||||
|
||||
# actually do the login
|
||||
session.session_login(player)
|
||||
|
||||
# post-login hooks
|
||||
player.at_post_login()
|
||||
if character:
|
||||
character.at_post_login()
|
||||
character.execute_cmd('look')
|
||||
else:
|
||||
player.execute_cmd('look')
|
||||
|
||||
player.at_post_login()
|
||||
character.at_post_login()
|
||||
# run look
|
||||
#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):
|
||||
"""
|
||||
|
|
@ -169,61 +201,69 @@ class CmdCreate(MuxCommand):
|
|||
return
|
||||
|
||||
# Run sanity and security checks
|
||||
|
||||
|
||||
if PlayerDB.objects.get_player_from_name(playername) or User.objects.filter(username=playername):
|
||||
# player already exists
|
||||
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
|
||||
session.msg("Sorry, there is already a player with that email address.")
|
||||
elif len(password) < 3:
|
||||
return
|
||||
if len(password) < 3:
|
||||
# too short password
|
||||
string = "Your password must be at least 3 characters or longer."
|
||||
string += "\n\rFor best security, make it at least 8 characters long, "
|
||||
string += "avoid making it a real word and mix numbers into it."
|
||||
session.msg(string)
|
||||
else:
|
||||
# everything's ok. Create the new player account
|
||||
try:
|
||||
default_home_id = ServerConfig.objects.conf("default_home")
|
||||
default_home = ObjectDB.objects.get_id(default_home_id)
|
||||
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
return
|
||||
|
||||
new_character = create.create_player(playername, email, password,
|
||||
permissions=permissions,
|
||||
location=default_home,
|
||||
typeclass=typeclass,
|
||||
home=default_home)
|
||||
# character safety features
|
||||
new_character.locks.delete("get")
|
||||
new_character.locks.add("get:perm(Wizards)")
|
||||
# everything's ok. Create the new player account.
|
||||
try:
|
||||
default_home_id = ServerConfig.objects.conf("default_home")
|
||||
default_home = ObjectDB.objects.get_id(default_home_id)
|
||||
|
||||
# set a default description
|
||||
new_character.db.desc = "This is a Player."
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
|
||||
new_character.db.FIRST_LOGIN = True
|
||||
new_player = new_character.player
|
||||
new_player.db.FIRST_LOGIN = True
|
||||
|
||||
# join the new player to the public channel
|
||||
pchanneldef = settings.CHANNEL_PUBLIC
|
||||
if pchanneldef:
|
||||
pchannel = Channel.objects.get_channel(pchanneldef[0])
|
||||
if not pchannel.connect_to(new_player):
|
||||
string = "New player '%s' could not connect to public channel!" % new_player.key
|
||||
logger.log_errmsg(string)
|
||||
new_character = create.create_player(playername, email, password,
|
||||
permissions=permissions,
|
||||
location=default_home,
|
||||
typeclass=typeclass,
|
||||
home=default_home)
|
||||
new_player = new_character.player
|
||||
|
||||
# character safety features
|
||||
new_character.locks.delete("get")
|
||||
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))
|
||||
|
||||
string = "A new account '%s' was created with the email address %s. Welcome!"
|
||||
string += "\n\nYou can now log with the command 'connect %s <your password>'."
|
||||
session.msg(string % (playername, email, email))
|
||||
except Exception:
|
||||
# we have to handle traceback ourselves at this point, if
|
||||
# we don't, errors will give no feedback.
|
||||
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
|
||||
session.msg(string % (traceback.format_exc()))
|
||||
logger.log_errmsg(traceback.format_exc())
|
||||
# set a default description
|
||||
new_character.db.desc = "This is a Player."
|
||||
|
||||
new_character.db.FIRST_LOGIN = True
|
||||
new_player = new_character.player
|
||||
new_player.db.FIRST_LOGIN = True
|
||||
|
||||
# join the new player to the public channel
|
||||
pchanneldef = settings.CHANNEL_PUBLIC
|
||||
if pchanneldef:
|
||||
pchannel = Channel.objects.get_channel(pchanneldef[0])
|
||||
if not pchannel.connect_to(new_player):
|
||||
string = "New player '%s' could not connect to public channel!" % new_player.key
|
||||
logger.log_errmsg(string)
|
||||
|
||||
string = "A new account '%s' was created with the email address %s. Welcome!"
|
||||
string += "\n\nYou can now log with the command 'connect %s <your password>'."
|
||||
session.msg(string % (playername, email, email))
|
||||
except Exception:
|
||||
# We are in the middle between logged in and -not, so we have to handle tracebacks
|
||||
# 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."
|
||||
session.msg(string % (traceback.format_exc()))
|
||||
logger.log_errmsg(traceback.format_exc())
|
||||
|
||||
class CmdQuit(MuxCommand):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -80,11 +80,16 @@ class ChannelCommand(command.Command):
|
|||
msg = "[%s] %s: %s" % (channel.key, caller.name, msg)
|
||||
# we can't use the utils.create function to make the Msg,
|
||||
# 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.channels = channel
|
||||
# send new message object to channel
|
||||
channel.msg(msgobj, from_obj=caller.player)
|
||||
channel.msg(msgobj, from_obj=sender)
|
||||
|
||||
class ChannelHandler(object):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -106,6 +106,16 @@ from src.utils import utils
|
|||
|
||||
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):
|
||||
"Always returns 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)
|
||||
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):
|
||||
"""
|
||||
Usage:
|
||||
|
|
@ -175,10 +208,21 @@ def dbref(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
return dbref == accessing_obj.id
|
||||
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):
|
||||
"Alias to dbref"
|
||||
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):
|
||||
"""
|
||||
Usage:
|
||||
|
|
|
|||
|
|
@ -223,7 +223,8 @@ class LockHandler(object):
|
|||
wlist.append("Lock: access type '%s' changed from '%s' to '%s' " % \
|
||||
(access_type, locks[access_type][2], 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))
|
||||
if 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
|
||||
put to a dummy value since no lock selection is made.
|
||||
"""
|
||||
if (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'user')
|
||||
and hasattr(accessing_obj.player.user, 'is_superuser')
|
||||
and accessing_obj.player.user.is_superuser):
|
||||
return True # always grant access to the superuser.
|
||||
if ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser)
|
||||
or (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser)
|
||||
or (hasattr(accessing_obj, 'get_player') and (accessing_obj.get_player()==None or accessing_obj.get_player().is_superuser))):
|
||||
return True
|
||||
|
||||
locks = self. _parse_lockstring(lockstring)
|
||||
for access_type in locks:
|
||||
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
|
||||
|
||||
# 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:
|
||||
# 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)
|
||||
|
||||
AT_MULTIMATCH_INPUT = utils.mod_import(*settings.SEARCH_AT_MULTIMATCH_INPUT.rsplit('.', 1))
|
||||
|
||||
class ObjectManager(TypedObjectManager):
|
||||
"""
|
||||
|
|
@ -172,7 +169,10 @@ class ObjectManager(TypedObjectManager):
|
|||
global_search=False,
|
||||
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.
|
||||
ostring: (string) The string to compare names against.
|
||||
|
|
@ -187,7 +187,7 @@ class ObjectManager(TypedObjectManager):
|
|||
if not ostring or not character:
|
||||
return None
|
||||
|
||||
if not location:
|
||||
if not location and hasattr(character, "location"):
|
||||
location = character.location
|
||||
|
||||
# Easiest case - dbref matching (always exact)
|
||||
|
|
@ -204,16 +204,17 @@ class ObjectManager(TypedObjectManager):
|
|||
if character and ostring in ['me', 'self']:
|
||||
return [character]
|
||||
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("*"):
|
||||
# Player search - try to find obj by its player's name
|
||||
player_match = self.get_object_with_player(ostring)
|
||||
if player_match is not None:
|
||||
return [player_match.player]
|
||||
|
||||
return [player_match]
|
||||
|
||||
# Search for keys, aliases or other attributes
|
||||
|
||||
search_locations = [None] # this means a global search
|
||||
|
|
@ -246,7 +247,7 @@ class ObjectManager(TypedObjectManager):
|
|||
matches = local_and_global_search(ostring, exact=True)
|
||||
if not matches:
|
||||
# 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:
|
||||
# Run search again, without match number:
|
||||
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.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
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.objects.manager import ObjectManager
|
||||
from src.players.models import PlayerDB
|
||||
from src.server.models import ServerConfig
|
||||
from src.commands.cmdsethandler import CmdSetHandler
|
||||
from src.commands import cmdhandler
|
||||
from src.scripts.scripthandler import ScriptHandler
|
||||
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
|
||||
|
||||
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
|
||||
AT_SEARCH_RESULT = mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -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:
|
||||
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 = models.ForeignKey("ObjectDB")
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
verbose_name = "Nickname"
|
||||
verbose_name_plural = "Nicknames"
|
||||
verbose_name = "Nickname for Objects"
|
||||
verbose_name_plural = "Nicknames Objects"
|
||||
unique_together = ("db_nick", "db_type", "db_obj")
|
||||
|
||||
class NickHandler(object):
|
||||
class ObjectNickHandler(TypeNickHandler):
|
||||
"""
|
||||
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.scripts = ScriptHandler(self)
|
||||
self.scripts.validate(init_mode=True)
|
||||
self.nicks = NickHandler(self)
|
||||
self.nicks = ObjectNickHandler(self)
|
||||
|
||||
# Wrapper properties to easily set database fields. These are
|
||||
# @property decorators that allows to access these fields using
|
||||
|
|
@ -312,7 +264,7 @@ class ObjectDB(TypedObject):
|
|||
loc = location
|
||||
elif ObjectDB.objects.dbref(location):
|
||||
# location is a dbref; search
|
||||
loc = ObjectDB.objects.dbref_search(location)
|
||||
loc = ObjectDB.objects.dbref_search(ocation)
|
||||
if loc and hasattr(loc,'dbobj'):
|
||||
loc = loc.dbobj
|
||||
else:
|
||||
|
|
@ -524,14 +476,11 @@ class ObjectDB(TypedObject):
|
|||
global_search=False,
|
||||
attribute_name=None,
|
||||
use_nicks=False, location=None,
|
||||
ignore_errors=False):
|
||||
ignore_errors=False, player=False):
|
||||
"""
|
||||
Perform a standard object search in the database, handling
|
||||
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.
|
||||
Obs - To find a player, append * to the
|
||||
start of ostring.
|
||||
|
|
@ -544,7 +493,16 @@ class ObjectDB(TypedObject):
|
|||
ignore_errors : Don't display any error messages even
|
||||
if there are none/multiple matches -
|
||||
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
|
||||
linked to the key in order to separate the matches from
|
||||
each other without showing the dbref explicitly. Default
|
||||
|
|
@ -554,22 +512,30 @@ class ObjectDB(TypedObject):
|
|||
etc.
|
||||
"""
|
||||
if use_nicks:
|
||||
if ostring.startswith('*'):
|
||||
if ostring.startswith('*') or player:
|
||||
# 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:
|
||||
# object nick replace
|
||||
ostring = self.nicks.get(ostring, nick_type="object")
|
||||
|
||||
results = ObjectDB.objects.object_search(self, ostring,
|
||||
global_search=global_search,
|
||||
attribute_name=attribute_name,
|
||||
location=location)
|
||||
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,
|
||||
global_search=global_search,
|
||||
attribute_name=attribute_name,
|
||||
location=location)
|
||||
|
||||
if ignore_errors:
|
||||
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
|
||||
|
|
@ -588,7 +554,7 @@ class ObjectDB(TypedObject):
|
|||
|
||||
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 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:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
|
|
@ -605,7 +571,7 @@ class ObjectDB(TypedObject):
|
|||
"""
|
||||
# This is an important function that must always work.
|
||||
# we use a different __getattribute__ to avoid recursive loops.
|
||||
|
||||
|
||||
if object.__getattribute__(self, 'player'):
|
||||
object.__getattribute__(self, 'player').msg(message, from_obj, data)
|
||||
|
||||
|
|
@ -796,9 +762,15 @@ class ObjectDB(TypedObject):
|
|||
return False
|
||||
|
||||
# See if we need to kick the player off.
|
||||
|
||||
for session in self.sessions:
|
||||
session.msg("Your character %s has been destroyed. Goodbye." % self.name)
|
||||
session.session_disconnect()
|
||||
session.msg("Your character %s has been destroyed." % self.name)
|
||||
#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:
|
||||
# self.player.user.is_active = False
|
||||
|
|
@ -811,6 +783,3 @@ class ObjectDB(TypedObject):
|
|||
# Perform the deletion of the object
|
||||
super(ObjectDB, self).delete()
|
||||
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,
|
||||
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
|
||||
# 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("get:all()") # pick up 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):
|
||||
"""
|
||||
|
|
@ -310,9 +314,11 @@ class Character(Object):
|
|||
def basetype_setup(self):
|
||||
"""
|
||||
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()
|
||||
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("call:false()") # no commands can be called on character
|
||||
|
||||
|
|
@ -348,9 +354,13 @@ class Room(Object):
|
|||
"""
|
||||
Simple setup, shown as an example
|
||||
(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()
|
||||
self.locks.add("puppet:false()") # would be weird to puppet a room ...
|
||||
self.locks.add("get:false()")
|
||||
|
||||
super(Room, self).basetype_setup()
|
||||
|
|
@ -371,9 +381,13 @@ class Exit(Object):
|
|||
def basetype_setup(self):
|
||||
"""
|
||||
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
|
||||
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("get:false()") # noone can pick up the exit
|
||||
|
||||
|
|
|
|||
|
|
@ -146,17 +146,13 @@ class PlayerManager(TypedObjectManager):
|
|||
|
||||
ostring = a string or database id.
|
||||
"""
|
||||
players = []
|
||||
try:
|
||||
# try dbref match
|
||||
dbref = int(ostring.strip('#'))
|
||||
players = self.filter(id=dbref)
|
||||
except Exception:
|
||||
pass
|
||||
if not players:
|
||||
players = self.filter(user__username=ostring)
|
||||
return players
|
||||
|
||||
ostring = ostring.lstrip("*")
|
||||
dbref = self.dbref(ostring)
|
||||
if dbref:
|
||||
matches = self.filter(id=dbref)
|
||||
if matches:
|
||||
return matches
|
||||
return self.filter(user__username__iexact=ostring)
|
||||
|
||||
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.contrib.auth.models import User
|
||||
from django.utils.encoding import smart_str
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
from src.players import manager
|
||||
from src.typeclasses.models import Attribute, TypedObject
|
||||
from src.utils import logger
|
||||
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||
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_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
|
||||
|
|
@ -116,6 +152,9 @@ class PlayerDB(TypedObject):
|
|||
# the in-game object connected to this player (if any).
|
||||
# Use the property 'obj' to access.
|
||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True)
|
||||
|
||||
# database storage of persistant cmdsets.
|
||||
db_cmdset_storage = models.TextField(null=True)
|
||||
|
||||
# Database manager
|
||||
objects = manager.PlayerManager()
|
||||
|
|
@ -123,6 +162,14 @@ class PlayerDB(TypedObject):
|
|||
class Meta:
|
||||
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
|
||||
# @property decorators that allows to access these fields using
|
||||
# normal python operations (without having to remember to save()
|
||||
|
|
@ -172,6 +219,26 @@ class PlayerDB(TypedObject):
|
|||
self.db_obj = None
|
||||
self.save()
|
||||
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:
|
||||
"Define Django meta options"
|
||||
|
|
@ -245,15 +312,23 @@ class PlayerDB(TypedObject):
|
|||
Evennia -> User
|
||||
This is the main route for sending data back to the user from the server.
|
||||
"""
|
||||
|
||||
if from_obj:
|
||||
try:
|
||||
from_obj.at_msg_send(outgoing_string, to_obj=self, data=data)
|
||||
except Exception:
|
||||
pass
|
||||
if object.__getattribute__(self, "character"):
|
||||
if self.character.at_msg_receive(outgoing_string, from_obj=from_obj, data=data):
|
||||
for session in object.__getattribute__(self, 'sessions'):
|
||||
session.msg(outgoing_string, 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'):
|
||||
session.msg(outgoing_string, data)
|
||||
|
||||
|
||||
def swap_character(self, new_character, delete_old_character=False):
|
||||
"""
|
||||
|
|
@ -261,3 +336,49 @@ class PlayerDB(TypedObject):
|
|||
"""
|
||||
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,19 +12,20 @@ instead for most things).
|
|||
"""
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
|
||||
from settings import CMDSET_OOC
|
||||
|
||||
class Player(TypeClass):
|
||||
"""
|
||||
Base typeclass for all Players.
|
||||
"""
|
||||
|
||||
def at_player_creation(self):
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
This sets up the basic properties for a player.
|
||||
Overload this with at_player_creation rather than
|
||||
changing this method.
|
||||
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
# the text encoding to use.
|
||||
self.db.encoding = "utf-8"
|
||||
|
||||
|
|
@ -35,6 +36,21 @@ class Player(TypeClass):
|
|||
self.locks.add("boot:perm(Wizards)")
|
||||
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
|
||||
# in the character object's typeclass. You
|
||||
# can often ignore these and rely on the
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
"""
|
||||
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
|
||||
sets up all the networking features. (this is done by
|
||||
game/evennia.py).
|
||||
sets up all the networking features. (this is done by automatically
|
||||
by game/evennia.py).
|
||||
|
||||
"""
|
||||
import time
|
||||
|
|
|
|||
|
|
@ -145,13 +145,12 @@ class SessionBase(object):
|
|||
and have to be done right after this function!
|
||||
"""
|
||||
if self.logged_in:
|
||||
character = self.get_character()
|
||||
if character:
|
||||
uaccount = character.player.user
|
||||
uaccount.last_login = datetime.now()
|
||||
uaccount.save()
|
||||
self.at_disconnect()
|
||||
self.logged_in = False
|
||||
player = self.get_player()
|
||||
uaccount = player.user
|
||||
uaccount.last_login = datetime.now()
|
||||
uaccount.save()
|
||||
self.at_disconnect()
|
||||
self.logged_in = False
|
||||
SESSIONS.remove_session(self)
|
||||
|
||||
def session_validate(self):
|
||||
|
|
@ -227,16 +226,18 @@ class SessionBase(object):
|
|||
return
|
||||
|
||||
# all other inputs, including empty inputs
|
||||
character = self.get_character()
|
||||
character = self.get_character()
|
||||
|
||||
if character:
|
||||
#print "loggedin _execute_cmd: '%s' __ %s" % (command_string, character)
|
||||
# normal operation.
|
||||
character.execute_cmd(command_string)
|
||||
else:
|
||||
#print "unloggedin _execute_cmd: '%s' __ %s" % (command_string, character)
|
||||
# we are not logged in yet; call cmdhandler directly
|
||||
cmdhandler.cmdhandler(self, command_string, unloggedin=True)
|
||||
if self.logged_in:
|
||||
# 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)
|
||||
self.update_session_counters()
|
||||
|
||||
def get_data_obj(self, **kwargs):
|
||||
|
|
|
|||
|
|
@ -136,21 +136,18 @@ DATABASE_PORT = ''
|
|||
###################################################
|
||||
|
||||
# An alternate command parser module to use
|
||||
# (if not set, uses 'src.commands.cmdparser')
|
||||
ALTERNATE_PARSER = ""
|
||||
COMMAND_PARSER = "src.commands.cmdparser.cmdparser"
|
||||
# How many space-separated words a command name may have
|
||||
# and still be identified as one single command
|
||||
# (e.g. 'push button' instead of 'pushbutton')
|
||||
COMMAND_MAXLEN = 3
|
||||
# The handler that outputs errors when searching
|
||||
# objects using object.search(). (If not set, uses
|
||||
# src.objects.object_search_funcs.handle_search_errors)
|
||||
ALTERNATE_OBJECT_SEARCH_ERROR_HANDLER = ""
|
||||
# objects using object.search().
|
||||
SEARCH_AT_RESULT = "src.commands.cmdparser.at_search_result"
|
||||
# The parser used in order to separate multiple
|
||||
# object matches (so you can separate between same-named
|
||||
# objects without using dbrefs). (If not set, uses
|
||||
# src.objects.object_search_funcs.object_multimatch_parser).
|
||||
ALTERNATE_OBJECT_SEARCH_MULTIMATCH_PARSER = ""
|
||||
# objects without using dbrefs).
|
||||
SEARCH_AT_MULTIMATCH_INPUT = "src.commands.cmdparser.at_multimatch_input"
|
||||
# The module holding text strings for the connection screen.
|
||||
# This module should contain one or more variables
|
||||
# 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
|
||||
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"
|
||||
# Command set for players without a character (ooc)
|
||||
CMDSET_OOC = "game.gamesrc.commands.basecmdset.OOCCmdSet"
|
||||
|
||||
###################################################
|
||||
# Default Object typeclasses
|
||||
|
|
|
|||
|
|
@ -294,6 +294,87 @@ class Attribute(SharedMemoryModel):
|
|||
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
|
||||
|
|
@ -992,9 +1073,12 @@ class TypedObject(SharedMemoryModel):
|
|||
|
||||
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.
|
||||
"""
|
||||
if self.player and self.player.is_superuser:
|
||||
return True
|
||||
|
||||
if not permstring:
|
||||
return False
|
||||
perm = permstring.lower()
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ def create_player(name, email, password,
|
|||
new_player = PlayerDB(db_key=name, user=new_user)
|
||||
new_player.save()
|
||||
|
||||
new_player.basetype_setup() # setup the basic locks and cmdset
|
||||
# call hook method (may override default permissions)
|
||||
new_player.at_player_creation()
|
||||
|
||||
|
|
|
|||
|
|
@ -173,8 +173,8 @@ def reset_loop():
|
|||
[m.locks.reset() for m in Msg.objects.all()]
|
||||
[c.locks.reset() for c in Channel.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()]
|
||||
[(p.typeclass(p), p.cmdset.reset(), p.locks.reset()) for p in PlayerDB.get_all_cached_instances()]
|
||||
|
||||
t2 = time.time()
|
||||
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
|
||||
|
||||
from src.objects.models import ObjectDB
|
||||
from src.players.models import PlayerDB
|
||||
from src.scripts.models import ScriptDB
|
||||
from src.comms.models import Msg, Channel
|
||||
from src.help.models import HelpEntry
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
# import objects this way to avoid circular import problems
|
||||
ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
|
||||
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
|
||||
|
|
|
|||
|
|
@ -20,3 +20,5 @@ class EvenniaTestSuiteRunner(DjangoTestSuiteRunner):
|
|||
test_labels = [applabel.rsplit('.', 1)[1] for applabel in settings.INSTALLED_APPS
|
||||
if (applabel.startswith('src.') or applabel.startswith('game.'))]
|
||||
return super(EvenniaTestSuiteRunner, self).build_suite(test_labels, extra_tests=extra_tests, **kwargs)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -235,14 +235,28 @@ def dbref(dbref):
|
|||
except Exception:
|
||||
return None
|
||||
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
|
||||
the unicode format. Note that one
|
||||
needs to encode it back to utf-8
|
||||
before writing to disk or printing.
|
||||
This decodes a suitable object to the unicode format. Note that
|
||||
one needs to encode it back to utf-8 before writing to disk or
|
||||
printing. Note that non-string objects are let through without
|
||||
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):
|
||||
try:
|
||||
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))
|
||||
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,
|
||||
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):
|
||||
try:
|
||||
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
|
||||
from parent. What differs this function from e.g. isinstance()
|
||||
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).
|
||||
"""
|
||||
|
||||
|
|
@ -480,10 +509,11 @@ def has_parent(basepath, obj):
|
|||
# instance. Not sure if one should defend against this.
|
||||
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
|
||||
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):
|
||||
|
|
@ -494,6 +524,7 @@ def mod_import(mod_path):
|
|||
"""
|
||||
from traceback import format_exc
|
||||
from twisted.python import log
|
||||
print errmsg
|
||||
|
||||
tracestring = format_exc()
|
||||
if tracestring:
|
||||
|
|
@ -507,23 +538,39 @@ def mod_import(mod_path):
|
|||
for line in errmsg.splitlines():
|
||||
log.msg('[EE] %s' % line)
|
||||
|
||||
if not os.path.isabs(mod_path):
|
||||
mod_path = os.path.abspath(mod_path)
|
||||
path, filename = mod_path.rsplit(os.path.sep, 1)
|
||||
modname = filename.rstrip('.py')
|
||||
# first try to import as a python path
|
||||
try:
|
||||
mod = __import__(mod_path, fromlist=["None"])
|
||||
except ImportError:
|
||||
|
||||
# try absolute path import instead
|
||||
|
||||
try:
|
||||
result = imp.find_module(modname, [path])
|
||||
except ImportError:
|
||||
log_trace("Could not find module '%s' (%s.py) at path '%s'" % (modname, modname, path))
|
||||
return
|
||||
try:
|
||||
mod = imp.load_module(modname, *result)
|
||||
except ImportError:
|
||||
log_trace("Could not find or import module %s at path '%s'" % (modname, path))
|
||||
mod = None
|
||||
# we have to close the file handle manually
|
||||
result[0].close()
|
||||
if not os.path.isabs(mod_path):
|
||||
mod_path = os.path.abspath(mod_path)
|
||||
path, filename = mod_path.rsplit(os.path.sep, 1)
|
||||
modname = filename.rstrip('.py')
|
||||
|
||||
try:
|
||||
result = imp.find_module(modname, [path])
|
||||
except ImportError:
|
||||
log_trace("Could not find module '%s' (%s.py) at path '%s'" % (modname, modname, path))
|
||||
return
|
||||
try:
|
||||
mod = imp.load_module(modname, *result)
|
||||
except ImportError:
|
||||
log_trace("Could not find or import module %s at path '%s'" % (modname, path))
|
||||
mod = None
|
||||
# we have to close the file handle manually
|
||||
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
|
||||
|
||||
def string_from_module(modpath, variable=None):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue