Cleaning some unnecessary whitespace, overall cleanup of various source codes.

This commit is contained in:
Griatch 2012-03-30 23:47:22 +02:00
parent d4c97d7df8
commit c0322c9eae
27 changed files with 1342 additions and 1318 deletions

View file

@ -1,6 +1,6 @@
#
# This sets up how models are displayed
# in the web admin interface.
# This sets up how models are displayed
# in the web admin interface.
#
from django import forms
@ -35,38 +35,38 @@ class ObjectCreateForm(forms.ModelForm):
db_typeclass_path = forms.CharField(label="Typeclass",initial="Change to (for example) %s or %s." % (settings.BASE_OBJECT_TYPECLASS, settings.BASE_CHARACTER_TYPECLASS),
widget=forms.TextInput(attrs={'size':'78'}),
help_text="This defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass. If you are creating a Character you should use the typeclass defined by settings.BASE_CHARACTER_TYPECLASS or one derived from that.")
db_permissions = forms.CharField(label="Permissions",
initial=settings.PERMISSION_PLAYER_DEFAULT,
db_permissions = forms.CharField(label="Permissions",
initial=settings.PERMISSION_PLAYER_DEFAULT,
required=False,
widget=forms.TextInput(attrs={'size':'78'}),
help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.")
db_cmdset_storage = forms.CharField(label="CmdSet",
db_cmdset_storage = forms.CharField(label="CmdSet",
initial=settings.CMDSET_DEFAULT,
required=False,
widget=forms.TextInput(attrs={'size':'78'}),
help_text="Most non-character objects don't need a cmdset and can leave this field blank.")
class ObjectEditForm(ObjectCreateForm):
"Form used for editing. Extends the create one with more fields"
db_lock_storage = forms.CharField(label="Locks",
required=False,
db_lock_storage = forms.CharField(label="Locks",
required=False,
widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}),
help_text="In-game lock definition string. If not given, defaults will be used. This string should be on the form <i>type:lockfunction(args);type2:lockfunction2(args);...")
class ObjectDBAdmin(admin.ModelAdmin):
class ObjectDBAdmin(admin.ModelAdmin):
list_display = ('id', 'db_key', 'db_location', 'db_player', 'db_typeclass_path')
list_display_links = ('id', 'db_key')
ordering = ['db_player', 'db_typeclass_path', 'id']
search_fields = ['^db_key', 'db_typeclass_path']
save_as = True
save_as = True
save_on_top = True
list_select_related = True
list_select_related = True
list_filter = ('db_permissions', 'db_location', 'db_typeclass_path')
# editing fields setup
@ -74,7 +74,7 @@ class ObjectDBAdmin(admin.ModelAdmin):
form = ObjectEditForm
fieldsets = (
(None, {
'fields': (('db_key','db_typeclass_path'), ('db_permissions', 'db_lock_storage'),
'fields': (('db_key','db_typeclass_path'), ('db_permissions', 'db_lock_storage'),
('db_location', 'db_home'), 'db_destination','db_cmdset_storage'
)}),
)
@ -88,7 +88,7 @@ class ObjectDBAdmin(admin.ModelAdmin):
add_form = ObjectCreateForm
add_fieldsets = (
(None, {
'fields': (('db_key','db_typeclass_path'), 'db_permissions',
'fields': (('db_key','db_typeclass_path'), 'db_permissions',
('db_location', 'db_home'), 'db_destination','db_cmdset_storage'
)}),
)
@ -116,8 +116,8 @@ class ObjectDBAdmin(admin.ModelAdmin):
obj = obj.typeclass
obj.basetype_setup()
obj.basetype_posthook_setup()
obj.at_object_creation()
obj.at_object_creation()
obj.at_init()
admin.site.register(ObjectDB, ObjectDBAdmin)

View file

@ -3,7 +3,7 @@ Custom manager for Objects.
"""
from django.conf import settings
from django.contrib.auth.models import User
from django.db.models.fields import exceptions
from django.db.models.fields import exceptions
from src.typeclasses.managers import TypedObjectManager
from src.typeclasses.managers import returns_typeclass, returns_typeclass_list
from src.utils import utils
@ -17,11 +17,11 @@ AT_MULTIMATCH_INPUT = utils.mod_import(*settings.SEARCH_AT_MULTIMATCH_INPUT.rspl
class ObjectManager(TypedObjectManager):
"""
This ObjectManager implementes methods for searching
and manipulating Objects directly from the database.
and manipulating Objects directly from the database.
Evennia-specific search methods (will return Typeclasses or
lists of Typeclasses, whereas Django-general methods will return
Querysets or database objects).
Querysets or database objects).
dbref (converter)
dbref_search
@ -41,19 +41,19 @@ class ObjectManager(TypedObjectManager):
copy_object
"""
#
# ObjectManager Get methods
# ObjectManager Get methods
#
# user/player related
@returns_typeclass
def get_object_with_user(self, user):
"""
Matches objects with obj.player.user matching the argument.
A player<->user is a one-to-relationship, so this always
returns just one result or None.
returns just one result or None.
user - may be a user object or user id.
"""
@ -61,26 +61,26 @@ class ObjectManager(TypedObjectManager):
uid = int(user)
except TypeError:
try:
uid = user.id
uid = user.id
except:
return None
try:
return self.get(db_player__user__id=uid)
except Exception:
return None
# This returns typeclass since get_object_with_user and get_dbref does.
# This returns typeclass since get_object_with_user and get_dbref does.
def get_object_with_player(self, search_string):
"""
Search for an object based on its player's name or dbref.
"""
Search for an object based on its player's name or dbref.
This search
is sometimes initiated by appending a * to the beginning of
the search criterion (e.g. in local_and_global_search).
the search criterion (e.g. in local_and_global_search).
search_string: (string) The name or dbref to search for.
"""
search_string = to_unicode(search_string).lstrip('*')
search_string = to_unicode(search_string).lstrip('*')
dbref = self.dbref(search_string)
if not dbref:
if not dbref:
# not a dbref. Search by name.
player_matches = User.objects.filter(username__iexact=search_string)
if player_matches:
@ -105,17 +105,17 @@ class ObjectManager(TypedObjectManager):
from src.objects.models import ObjAttribute
lstring = ""
if location:
lstring = ", db_obj__db_location=location"
lstring = ", db_obj__db_location=location"
attrs = eval("ObjAttribute.objects.filter(db_key=attribute_name%s)" % lstring)
return [attr.obj for attr in attrs]
@returns_typeclass_list
def get_objs_with_attr_match(self, attribute_name, attribute_value, location=None, exact=False):
"""
Returns all objects having the valid
Returns all objects having the valid
attrname set to the given value. Note that no conversion is made
to attribute_value, and so it can accept also non-strings.
"""
"""
from src.objects.models import ObjAttribute
lstring = ""
if location:
@ -123,27 +123,27 @@ class ObjectManager(TypedObjectManager):
attrs = eval("ObjAttribute.objects.filter(db_key=attribute_name%s)" % lstring)
# since attribute values are pickled in database, we cannot search directly, but
# must loop through the results. .
if exact:
if exact:
return [attr.obj for attr in attrs if attribute_value == attr.value]
else:
return [attr.obj for attr in attrs if to_unicode(attribute_value) in str(attr.value)]
@returns_typeclass_list
def get_objs_with_db_property(self, property_name, location=None):
"""
Returns all objects having a given db field property.
property_name = search string
property_name = search string
location - actual location object to restrict to
"""
lstring = ""
if location:
lstring = ".filter(db_location=location)"
lstring = ".filter(db_location=location)"
try:
return eval("self.exclude(db_%s=None)%s" % (property_name, lstring))
except exceptions.FieldError:
return []
@returns_typeclass_list
def get_objs_with_db_property_match(self, property_name, property_value, location, exact=False):
"""
@ -165,7 +165,7 @@ class ObjectManager(TypedObjectManager):
def get_objs_with_key_or_alias(self, ostring, location, exact=False):
"""
Returns objects based on key or alias match
"""
"""
lstring_key, lstring_alias, estring = "", "", "icontains"
if location:
lstring_key = ", db_location=location"
@ -181,7 +181,7 @@ class ObjectManager(TypedObjectManager):
return matches
# main search methods and helper functions
@returns_typeclass_list
def get_contents(self, location, excludeobj=None):
"""
@ -192,31 +192,40 @@ class ObjectManager(TypedObjectManager):
if excludeobj:
estring = ".exclude(db_key=excludeobj)"
return eval("self.filter(db_location__id=location.id)%s" % estring)
@returns_typeclass_list
def object_search(self, ostring, caller=None,
global_search=False,
global_search=False,
attribute_name=None, location=None):
"""
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. Always returns a list.
Arguments:
ostring: (string) The string to compare names against.
Can be a dbref. If name is appended by *, a player is searched for.
caller: (Object) The object performing the search.
global_search: Search all objects, not just the current location/inventory
attribute_name: (string) Which attribute to search in each object.
If None, the default 'key' attribute is used.
location: If None, character.location will be used.
Can be a dbref. If name is appended by *, a player is searched for.
caller: (Object) The optional object performing the search.
global_search (bool). Defaults to False. If a caller is defined, search will
be restricted to the contents of caller.location unless global_search
is True. If no caller is given (or the caller has no location), a
global search is assumed automatically.
attribute_name: (string) Which object attribute to match ostring against. If not
set, the "key" and "aliases" properties are searched in order.
location (Object): If set, this location's contents will be used to limit the search instead
of the callers. global_search will override this argument
Returns:
A list of matching objects (or a list with one unique match)
"""
ostring = to_unicode(ostring, force_string=True)
if not ostring:
return []
return []
# Easiest case - dbref matching (always exact)
# Easiest case - dbref matching (always exact)
dbref = self.dbref(ostring)
if dbref:
dbref_match = self.dbref_search(dbref)
@ -229,12 +238,12 @@ class ObjectManager(TypedObjectManager):
# Test some common self-references
if location and ostring == 'here':
return [location]
return [location]
if caller and ostring in ('me', 'self'):
return [caller]
if caller and ostring in ('*me', '*self'):
return [caller]
if caller and ostring in ('*me', '*self'):
return [caller]
# Test if we are looking for an object controlled by a
# specific player
@ -244,24 +253,24 @@ class ObjectManager(TypedObjectManager):
player_match = self.get_object_with_player(ostring)
if player_match is not None:
return [player_match]
# Search for keys, aliases or other attributes
search_locations = [None] # this means a global search
if not global_search and location:
# Test if we are referring to the current room
if location and (ostring.lower() == location.key.lower()
if location and (ostring.lower() == location.key.lower()
or ostring.lower() in [alias.lower() for alias in location.aliases]):
return [location]
# otherwise, setup the locations to search in
# otherwise, setup the locations to search in
search_locations = [location]
if caller:
search_locations.append(caller)
def local_and_global_search(ostring, exact=False):
"Helper method for searching objects"
matches = []
for location in search_locations:
"Helper method for searching objects"
matches = []
for location in search_locations:
if attribute_name:
# Attribute/property search. First, search for db_<attrname> matches on the model
matches.extend(self.get_objs_with_db_property_match(attribute_name, ostring, location, exact))
@ -269,14 +278,14 @@ class ObjectManager(TypedObjectManager):
# Next, try Attribute matches
matches.extend(self.get_objs_with_attr_match(attribute_name, ostring, location, exact))
else:
# No attribute/property named. Do a normal key/alias-search
# No attribute/property named. Do a normal key/alias-search
matches.extend(self.get_objs_with_key_or_alias(ostring, location, exact))
return matches
# Search through all possibilities.
match_number = None
matches = local_and_global_search(ostring, exact=True)
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 = AT_MULTIMATCH_INPUT(ostring)
@ -289,7 +298,7 @@ class ObjectManager(TypedObjectManager):
elif len(matches) > 1:
# multiple matches already. Run a fuzzy search. This catches partial matches (suggestions)
matches = local_and_global_search(ostring, exact=False)
# deal with the result
if len(matches) > 1 and match_number != None:
# We have multiple matches, but a N-type match number is available to separate them.
@ -299,21 +308,21 @@ class ObjectManager(TypedObjectManager):
pass
# This is always a list.
return matches
#
# ObjectManager Copy method
#
def copy_object(self, original_object, new_key=None,
new_location=None, new_player=None, new_home=None,
new_location=None, new_player=None, new_home=None,
new_permissions=None, new_locks=None, new_aliases=None, new_destination=None):
"""
Create and return a new object as a copy of the original object. All will
be identical to the original except for the arguments given specifically
be identical to the original except for the arguments given specifically
to this method.
original_object (obj) - the object to make a copy from
new_key (str) - name the copy differently from the original.
new_key (str) - name the copy differently from the original.
new_location (obj) - if not None, change the location
new_home (obj) - if not None, change the Home
new_aliases (list of strings) - if not None, change object aliases.
@ -322,7 +331,7 @@ class ObjectManager(TypedObjectManager):
# get all the object's stats
typeclass_path = original_object.typeclass_path
if not new_key:
if not new_key:
new_key = original_object.key
if not new_location:
new_location = original_object.location
@ -331,36 +340,36 @@ class ObjectManager(TypedObjectManager):
if not new_player:
new_player = original_object.player
if not new_aliases:
new_aliases = original_object.aliases
new_aliases = original_object.aliases
if not new_locks:
new_locks = original_object.db_lock_storage
if not new_permissions:
new_permissions = original_object.permissions
new_permissions = original_object.permissions
if not new_destination:
new_destination = original_object.destination
# create new object
from src.utils import create
# create new object
from src.utils import create
from src.scripts.models import ScriptDB
new_object = create.create_object(typeclass_path, key=new_key, location=new_location,
home=new_home, player=new_player, permissions=new_permissions,
home=new_home, player=new_player, permissions=new_permissions,
locks=new_locks, aliases=new_aliases, destination=new_destination)
if not new_object:
return None
return None
# copy over all attributes from old to new.
# copy over all attributes from old to new.
for attr in original_object.get_all_attributes():
new_object.set_attribute(attr.key, attr.value)
# copy over all cmdsets, if any
# copy over all cmdsets, if any
for icmdset, cmdset in enumerate(original_object.cmdset.all()):
if icmdset == 0:
new_object.cmdset.add_default(cmdset)
else:
new_object.cmdset.add(cmdset)
# copy over all scripts, if any
# copy over all scripts, if any
for script in original_object.scripts.all():
ScriptDB.objects.copy_script(script, new_obj=new_object.dbobj)
return new_object

View file

@ -1,6 +1,6 @@
"""
This module defines the database models for all in-game objects, that
is, all objects that has an actual existence in-game.
is, all objects that has an actual existence in-game.
Each database object is 'decorated' with a 'typeclass', a normal
python class that implements all the various logics needed by the game
@ -66,11 +66,11 @@ class Alias(SharedMemoryModel):
This model holds a range of alternate names for an object.
These are intrinsic properties of the object. The split
is so as to allow for effective global searches also by
alias.
"""
alias.
"""
db_key = models.CharField('alias', max_length=255, db_index=True)
db_obj = models.ForeignKey("ObjectDB", verbose_name='object')
class Meta:
"Define Django meta options"
verbose_name = "Object alias"
@ -79,8 +79,8 @@ class Alias(SharedMemoryModel):
return u"%s" % self.db_key
def __str__(self):
return str(self.db_key)
#------------------------------------------------------------
#
@ -90,11 +90,11 @@ class Alias(SharedMemoryModel):
class ObjectNick(TypeNick):
"""
The default nick types used by Evennia are:
The default nick types used by Evennia are:
inputline (default) - match against all input
player - match against player searches
obj - match against object searches
obj - match against object searches
channel - used to store own names for channels
"""
db_obj = models.ForeignKey("ObjectDB", verbose_name='object')
@ -108,7 +108,7 @@ class ObjectNick(TypeNick):
class ObjectNickHandler(TypeNickHandler):
"""
Handles nick access and setting. Accessed through ObjectDB.nicks
"""
"""
NickClass = ObjectNick
@ -126,7 +126,7 @@ class ObjectDB(TypedObject):
Note that the base objectdb is very simple, with
few defined fields. Use attributes to extend your
type class with new database-stored variables.
type class with new database-stored variables.
The TypedObject supplies the following (inherited) properties:
key - main name
@ -134,11 +134,11 @@ class ObjectDB(TypedObject):
typeclass_path - the path to the decorating typeclass
typeclass - auto-linked typeclass
date_created - time stamp of object creation
permissions - perm strings
permissions - perm strings
locks - lock definitions (handler)
dbref - #id of object
dbref - #id of object
db - persistent attribute storage
ndb - non-persistent attribute storage
ndb - non-persistent attribute storage
The ObjectDB adds the following properties:
player - optional connected player
@ -148,7 +148,7 @@ class ObjectDB(TypedObject):
scripts - scripts assigned to object (handler from typeclass)
cmdset - active cmdset on object (handler from typeclass)
aliases - aliases for this object (property)
nicks - nicknames for *other* things in Evennia (handler)
nicks - nicknames for *other* things in Evennia (handler)
sessions - sessions connected to this object (see also player)
has_player - bool if an active player is currently connected
contents - other objects having this object as location
@ -160,7 +160,7 @@ class ObjectDB(TypedObject):
#
#
# inherited fields (from TypedObject):
# db_key (also 'name' works), db_typeclass_path, db_date_created,
# db_key (also 'name' works), db_typeclass_path, db_date_created,
# db_permissions
#
# These databse fields (including the inherited ones) are all set
@ -168,11 +168,11 @@ class ObjectDB(TypedObject):
# but withtout the db_* prefix.
# If this is a character object, the player is connected here.
db_player = models.ForeignKey("players.PlayerDB", blank=True, null=True, verbose_name='player',
help_text='a Player connected to this object, if any.')
db_player = models.ForeignKey("players.PlayerDB", blank=True, null=True, verbose_name='player',
help_text='a Player connected to this object, if any.')
# The location in the game world. Since this one is likely
# to change often, we set this with the 'location' property
# to transparently handle Typeclassing.
# to transparently handle Typeclassing.
db_location = models.ForeignKey('self', related_name="locations_set",db_index=True,
blank=True, null=True, verbose_name='game location')
# a safety location, this usually don't change much.
@ -193,24 +193,24 @@ class ObjectDB(TypedObject):
def __init__(self, *args, **kwargs):
"Parent must be initialized first."
TypedObject.__init__(self, *args, **kwargs)
# handlers
TypedObject.__init__(self, *args, **kwargs)
# handlers
self.cmdset = CmdSetHandler(self)
self.cmdset.update(init_mode=True)
self.scripts = ScriptHandler(self)
self.nicks = ObjectNickHandler(self)
self.nicks = ObjectNickHandler(self)
# store the attribute class
# 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()
# etc). So e.g. a property 'attr' has a get/set/del decorator
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# aliases property (wraps (db_aliases)
#@property
#@property
def aliases_get(self):
"Getter. Allows for value = self.aliases"
try:
@ -218,10 +218,10 @@ class ObjectDB(TypedObject):
except AttributeError:
aliases = list(Alias.objects.filter(db_obj=self).values_list("db_key", flat=True))
SA(self, "_cached_aliases", aliases)
return aliases
return aliases
#@aliases.setter
def aliases_set(self, aliases):
"Setter. Allows for self.aliases = value"
"Setter. Allows for self.aliases = value"
for alias in make_iter(aliases):
new_alias = Alias(db_key=alias, db_obj=self)
new_alias.save()
@ -258,121 +258,121 @@ class ObjectDB(TypedObject):
player = property(player_get, player_set, player_del)
# location property (wraps db_location)
#@property
#@property
def location_get(self):
"Getter. Allows for value = self.location."
loc = get_cache(self, "location")
if loc:
return loc.typeclass
return None
return None
#@location.setter
def location_set(self, location):
"Setter. Allows for self.location = location"
try:
if location == None or type(location) == ObjectDB:
# location is None or a valid object
loc = location
loc = location
elif ObjectDB.objects.dbref(location):
# location is a dbref; search
loc = ObjectDB.objects.dbref_search(location)
if loc and hasattr(loc,'dbobj'):
loc = loc.dbobj
else:
loc = location.dbobj
else:
loc = location.dbobj
loc = location.dbobj
else:
loc = location.dbobj
set_cache(self, "location", loc)
except Exception:
string = "Cannot set location: "
string += "%s is not a valid location."
string += "%s is not a valid location."
self.msg(string % location)
logger.log_trace(string)
raise
raise
#@location.deleter
def location_del(self):
"Deleter. Allows for del self.location"
self.db_location = None
self.db_location = None
self.save()
del_cache()
location = property(location_get, location_set, location_del)
# home property (wraps db_home)
#@property
#@property
def home_get(self):
"Getter. Allows for value = self.home"
home = get_cache(self, "home")
if home:
return home.typeclass
return None
return None
#@home.setter
def home_set(self, home):
"Setter. Allows for self.home = value"
try:
if home == None or type(home) == ObjectDB:
hom = home
hom = home
elif ObjectDB.objects.dbref(home):
hom = ObjectDB.objects.dbref_search(home)
if hom and hasattr(hom,'dbobj'):
hom = hom.dbobj
else:
hom = home.dbobj
else:
hom = home.dbobj
hom = home.dbobj
else:
hom = home.dbobj
set_cache(self, "home", hom)
except Exception:
string = "Cannot set home: "
string += "%s is not a valid home."
string += "%s is not a valid home."
self.msg(string % home)
logger.log_trace(string)
#raise
#raise
#@home.deleter
def home_del(self):
"Deleter. Allows for del self.home."
self.db_home = None
self.db_home = None
self.save()
del_cache(self, "home")
home = property(home_get, home_set, home_del)
# destination property (wraps db_destination)
#@property
#@property
def destination_get(self):
"Getter. Allows for value = self.destination."
dest = get_cache(self, "destination")
if dest:
return dest.typeclass
return None
return None
#@destination.setter
def destination_set(self, destination):
"Setter. Allows for self.destination = destination"
try:
if destination == None or type(destination) == ObjectDB:
# destination is None or a valid object
dest = destination
dest = destination
elif ObjectDB.objects.dbref(destination):
# destination is a dbref; search
dest = ObjectDB.objects.dbref_search(destination)
if dest and hasattr(dest,'dbobj'):
dest = dest.dbobj
else:
dest = destination.dbobj
else:
dest = destination.dbobj
dest = destination.dbobj
else:
dest = destination.dbobj
set_cache(self, "destination", dest)
except Exception:
string = "Cannot set destination: "
string += "%s is not a valid destination."
string += "%s is not a valid destination."
self.msg(string % destination)
logger.log_trace(string)
raise
raise
#@destination.deleter
def destination_del(self):
"Deleter. Allows for del self.destination"
self.db_destination = None
self.db_destination = None
self.save()
del_cache(self, "destination")
destination = property(destination_get, destination_set, destination_del)
# cmdset_storage property.
# cmdset_storage property.
# This seems very sensitive to caching, so leaving it be for now. /Griatch
#@property
def cmdset_storage_get(self):
@ -385,7 +385,7 @@ class ObjectDB(TypedObject):
"Setter. Allows for self.name = value. Stores as a comma-separated string."
value = ",".join(str(val).strip() for val in make_iter(value))
self.db_cmdset_storage = value
self.save()
self.save()
#@cmdset_storage.deleter
def cmdset_storage_del(self):
"Deleter. Allows for del self.name"
@ -400,12 +400,12 @@ class ObjectDB(TypedObject):
#
# ObjectDB class access methods/properties
#
#
# this is required to properly handle attributes and typeclass loading.
#attribute_model_path = "src.objects.models"
#attribute_model_name = "ObjAttribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
attribute_class = ObjAttribute
db_model_name = "objectdb" # used by attributes to safely store objects
@ -420,13 +420,13 @@ class ObjectDB(TypedObject):
"""
Retrieve sessions connected to this object.
"""
# if the player is not connected, this will simply be an empty list.
# if the player is not connected, this will simply be an empty list.
if self.player:
return self.player.sessions
return []
sessions = property(sessions_get)
#@property
#@property
def has_player_get(self):
"""
Convenience function for checking if an active player is
@ -436,13 +436,13 @@ class ObjectDB(TypedObject):
has_player = property(has_player_get)
is_player = property(has_player_get)
#@property
#@property
def is_superuser_get(self):
"Check if user has a player, and if so, if it is a superuser."
return any(self.sessions) and self.player.is_superuser
is_superuser = property(is_superuser_get)
#@property
#@property
def contents_get(self, exclude=None):
"""
Returns the contents of this object, i.e. all
@ -461,11 +461,11 @@ class ObjectDB(TypedObject):
if exi.destination]
exits = property(exits_get)
#
# Main Search method
#
def search(self, ostring,
global_search=False,
attribute_name=None,
@ -474,49 +474,49 @@ class ObjectDB(TypedObject):
"""
Perform a standard object search in the database, handling
multiple results and lack thereof gracefully.
ostring: (str) The string to match object names against.
Obs - To find a player, append * to the
start of ostring.
start of ostring.
global_search: Search all objects, not just the current
location/inventory
attribute_name: (string) Which attribute to match
(if None, uses default 'name')
use_nicks : Use nickname replace (off by default)
use_nicks : Use nickname replace (off by default)
location : If None, use caller's current location
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.
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.
Returns - a unique Object/Player match or None. All error
messages are handled by system-commands and the parser-handlers
specified in settings.
specified in settings.
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.
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
syntax for this is 'N-searchword'. So for example, if there
are three objects in the room all named 'ball', you could
address the individual ball as '1-ball', '2-ball', '3-ball'
etc.
etc.
"""
if use_nicks:
if ostring.startswith('*') or player:
# player nick replace
# player nick replace
ostring = self.nicks.get(ostring.lstrip('*'), nick_type="player")
if not player:
ostring = "*%s" % ostring
else:
# object nick replace
# object nick replace
ostring = self.nicks.get(ostring, nick_type="object")
if player:
@ -525,11 +525,11 @@ class ObjectDB(TypedObject):
else:
results = PlayerDB.objects.player_search(ostring.lstrip('*'))
else:
results = ObjectDB.objects.object_search(ostring, caller=self,
results = ObjectDB.objects.object_search(ostring, caller=self,
global_search=global_search,
attribute_name=attribute_name,
location=location)
if ignore_errors:
return results
# this import is cache after the first call.
@ -538,50 +538,50 @@ class ObjectDB(TypedObject):
#
# Execution/action methods
#
def execute_cmd(self, raw_string):
"""
Do something as this object. This command transparently
lets its typeclass execute the command. Evennia also calls
this method whenever the player sends a command on the command line.
Argument:
Argument:
raw_string (string) - raw command input
Returns Deferred - this is an asynchronous Twisted object that will
not fire until the command has actually finished executing. To overload
this one needs to attach callback functions to it, with addCallback(function).
this one needs to attach callback functions to it, with addCallback(function).
This function will be called with an eventual return value from the command
execution.
execution.
This return is not used at all by Evennia by default, but might be useful
for coders intending to implement some sort of nested command structure.
"""
for coders intending to implement some sort of nested command structure.
"""
# nick replacement - we require full-word matching.
# do text encoding conversion
# do text encoding conversion
raw_string = 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 ObjectNick.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
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
break
return cmdhandler.cmdhandler(self.typeclass, raw_string)
def msg(self, message, from_obj=None, data=None):
"""
Emits something to any sessions attached to the object.
message (str): The message to send
from_obj (obj): object that is sending.
data (object): an optional data object that may or may not
be used by the protocol.
be used by the protocol.
"""
# This is an important function that must always work.
# 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=from_obj, data=data)
@ -589,7 +589,7 @@ class ObjectDB(TypedObject):
"Deprecated. Alias for msg"
logger.log_depmsg("emit_to() is deprecated. Use msg() instead.")
self.msg(message, from_obj, data)
def msg_contents(self, message, exclude=None, from_obj=None, data=None):
"""
Emits something to all objects inside an object.
@ -608,7 +608,7 @@ class ObjectDB(TypedObject):
"Deprecated. Alias for msg_contents"
logger.log_depmsg("emit_to_contents() is deprecated. Use msg_contents() instead.")
self.msg_contents(message, exclude=exclude, from_obj=from_obj, data=data)
def move_to(self, destination, quiet=False,
emit_to_obj=None, use_destination=True):
"""
@ -618,19 +618,19 @@ class ObjectDB(TypedObject):
exit object (i.e. it has "destination"!=None), the move_to will
happen to this destination and -not- into the exit object itself, unless
use_destination=False. Note that no lock checks are done by this function,
such things are assumed to have been handled before calling move_to.
such things are assumed to have been handled before calling move_to.
destination: (Object) Reference to the object to move to. This
can also be an exit object, in which case the destination
property is used as destination.
property is used as destination.
quiet: (bool) If true, don't emit left/arrived messages.
emit_to_obj: (Object) object to receive error messages
use_destination (bool): Default is for objects to use the "destination" property
of destinations as the target to move to. Turning off this
keyword allows objects to move "inside" exit objects.
keyword allows objects to move "inside" exit objects.
Returns True/False depending on if there were problems with the move. This method
may also return various error messages to the emit_to_obj.
may also return various error messages to the emit_to_obj.
"""
def logerr(string=""):
trc = traceback.format_exc()
@ -644,7 +644,7 @@ class ObjectDB(TypedObject):
if not destination:
emit_to_obj.msg("The destination doesn't exist.")
return
return
if destination.destination:
# traverse exits
destination = destination.destination
@ -658,8 +658,8 @@ class ObjectDB(TypedObject):
#emit_to_obj.msg(errtxt % "at_before_move()")
#logger.log_trace()
return False
# Save the old location
# Save the old location
source_location = self.location
if not source_location:
# there was some error in placing this room.
@ -678,16 +678,16 @@ class ObjectDB(TypedObject):
#emit_to_obj.msg(errtxt % "at_object_leave()")
#logger.log_trace()
return False
if not quiet:
#tell the old room we are leaving
try:
self.announce_move_from(destination)
self.announce_move_from(destination)
except Exception:
logerr(errtxt % "at_announce_move()")
logerr(errtxt % "at_announce_move()")
#emit_to_obj.msg(errtxt % "at_announce_move()" )
#logger.log_trace()
return False
return False
# Perform move
try:
@ -695,18 +695,18 @@ class ObjectDB(TypedObject):
except Exception:
emit_to_obj.msg(errtxt % "location change")
logger.log_trace()
return False
return False
if not quiet:
# Tell the new room we are there.
# Tell the new room we are there.
try:
self.announce_move_to(source_location)
except Exception:
logerr(errtxt % "announce_move_to()")
#emit_to_obj.msg(errtxt % "announce_move_to()")
#logger.log_trace()
return False
return False
# Perform eventual extra commands on the receiving location
# (the object has already arrived at this point)
try:
@ -715,7 +715,7 @@ class ObjectDB(TypedObject):
logerr(errtxt % "at_object_receive()")
#emit_to_obj.msg(errtxt % "at_object_receive()")
#logger.log_trace()
return False
return False
# Execute eventual extra commands on this object after moving it
# (usually calling 'look')
@ -725,13 +725,13 @@ class ObjectDB(TypedObject):
logerr(errtxt % "at_after_move")
#emit_to_obj.msg(errtxt % "at_after_move()")
#logger.log_trace()
return False
return True
return False
return True
#
# Object Swap, Delete and Cleanup methods
#
# Object Swap, Delete and Cleanup methods
#
def clear_exits(self):
"""
Destroys all of the exits and any exits pointing to this
@ -745,7 +745,7 @@ class ObjectDB(TypedObject):
def clear_contents(self):
"""
Moves all objects (players/things) to their home
location or to default home.
location or to default home.
"""
# Gather up everything that thinks this is its location.
objs = ObjectDB.objects.filter(db_location=self)
@ -754,29 +754,29 @@ class ObjectDB(TypedObject):
default_home = ObjectDB.objects.get(id=default_home_id)
if default_home.id == self.id:
# we are deleting default home!
default_home = None
default_home = None
except Exception:
string = "Could not find default home '(#%d)'."
logger.log_errmsg(string % default_home_id)
default_home = None
default_home = None
for obj in objs:
home = obj.home
for obj in objs:
home = obj.home
# Obviously, we can't send it back to here.
if not home or (home and home.id == self.id):
obj.home = default_home
obj.home = default_home
# If for some reason it's still None...
if not obj.home:
string = "Missing default home, '%s(#%d)' "
string += "now has a null location."
obj.location = None
obj.location = None
obj.msg("Something went wrong! You are dumped into nowhere. Contact an admin.")
logger.log_errmsg(string % (obj.name, obj.id))
return
return
if obj.has_player:
if home:
if home:
string = "Your current location has ceased to exist,"
string += " moving you to %s(#%d)."
obj.msg(string % (home.name, home.id))
@ -787,22 +787,22 @@ class ObjectDB(TypedObject):
obj.move_to(home)
def copy(self, new_key=None):
"""
"""
Makes an identical copy of this object. If you want to customize the copy by
changing some settings, use ObjectDB.object.copy_object() directly.
new_key (string) - new key/name of copied object. If new_key is not specified, the copy will be named
<old_key>_copy by default.
Returns: Object (copy of this one)
<old_key>_copy by default.
Returns: Object (copy of this one)
"""
if not new_key:
new_key = "%s_copy" % self.key
return ObjectDB.objects.copy_object(self, new_key=new_key)
delete_iter = 0
def delete(self):
def delete(self):
"""
Deletes this object.
Deletes this object.
Before deletion, this method makes sure to move all contained
objects to their respective home locations, as well as clean
up all exits to/from the object.
@ -815,7 +815,7 @@ class ObjectDB(TypedObject):
if not self.at_object_delete():
# this is an extra pre-check
# run before deletion mechanism
# is kicked into gear.
# is kicked into gear.
self.delete_iter == 0
return False
@ -825,17 +825,17 @@ class ObjectDB(TypedObject):
for session in self.sessions:
session.msg("Your character %s has been destroyed." % self.name)
# no need to disconnect, Player just jumps to OOC mode.
# no need to disconnect, Player just jumps to OOC mode.
# sever the connection (important!)
if object.__getattribute__(self, 'player') and self.player:
self.player.character = None
self.player = None
self.player = None
for script in self.scripts.all():
script.stop()
# if self.player:
# self.player.user.is_active = False
# self.player.user.is_active = False
# self.player.user.save(
# Destroy any exits to and from this room, if any
@ -844,4 +844,4 @@ class ObjectDB(TypedObject):
self.clear_contents()
# Perform the deletion of the object
super(ObjectDB, self).delete()
return True
return True

View file

@ -1,5 +1,5 @@
"""
This is the basis of the typeclass system.
This is the basis of the typeclass system.
The idea is have the object as a normal class with the
database-connection tied to itself through a property.
@ -19,15 +19,15 @@ from src.typeclasses.typeclass import TypeClass
from src.commands import cmdset, command
#
# Base class to inherit from.
# Base class to inherit from.
#
class Object(TypeClass):
"""
This is the base class for all in-game objects.
Inherit from this to create different types of
objects in the game.
"""
objects in the game.
"""
def __init__(self, dbobj):
"""
@ -39,18 +39,18 @@ class Object(TypeClass):
seen in src.object.objects).
Object Typeclass API:
Object Typeclass API:
* Available properties (only available on initiated typeclass objects)
key (string) - name of object
key (string) - name of object
name (string)- same as key
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
dbref (int, read-only) - unique #id-number. Also "id" can be used.
dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
date_created (string) - time stamp of object creation
permissions (list of strings) - list of permission strings
permissions (list of strings) - list of permission strings
player (Player) - controlling player (will also return offline player)
location (Object) - current location. Is None if this is a room
@ -59,19 +59,19 @@ class Object(TypeClass):
has_player (bool, read-only)- will only return *connected* players
contents (list of Objects, read-only) - returns all objects inside this object (including exits)
exits (list of Objects, read-only) - returns all exits from this object, if any
destination (Object) - only set if this object is an exit.
destination (Object) - only set if this object is an exit.
is_superuser (bool, read-only) - True/False if this user is a superuser
* Handlers available
* Handlers available
locks - lock-handler: use locks.add() to add new lock strings
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
scripts - script-handler. Add new scripts to object with scripts.add()
cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
nicks - nick-handler. New nicks with nicks.add().
* Helper methods (see src.objects.objects.py for full headers)
* Helper methods (see src.objects.objects.py for full headers)
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False)
execute_cmd(raw_string)
@ -90,15 +90,15 @@ class Object(TypeClass):
basetype_setup() - only called once, used for behind-the-scenes setup. Normally not modified.
basetype_posthook_setup() - customization in basetype, after the object has been created; Normally not modified.
at_object_creation() - only called once, when object is first created. Object customizations go here.
at_object_creation() - only called once, when object is first created. Object customizations go here.
at_object_delete() - called just before deleting an object. If returning False, deletion is aborted. Note that all objects
inside a deleted object are automatically moved to their <home>, they don't need to be removed here.
inside a deleted object are automatically moved to their <home>, they don't need to be removed here.
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
at_cmdset_get() - this is called just before the command handler requests a cmdset from this object
at_first_login() - (player-controlled objects only) called once, the very first time user logs in.
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
at_cmdset_get() - this is called just before the command handler requests a cmdset from this object
at_first_login() - (player-controlled objects only) called once, the very first time user logs in.
at_pre_login() - (player-controlled objects only) called every time the user connects, after they have identified, before other setup
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world.
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world.
at_disconnect() - (player-controlled objects only) called just before the user disconnects (or goes linkless)
at_server_reload() - called before server is reloaded
at_server_shutdown() - called just before server is fully shut down
@ -111,19 +111,19 @@ class Object(TypeClass):
at_object_receive(obj, source_location) - called when this object receives another object
at_before_traverse(traversing_object) - (exit-objects only) called just before an object traverses this object
at_after_traverse(traversing_object, source_location) - (exit-objects only) called just after a traversal has happened.
at_after_traverse(traversing_object, source_location) - (exit-objects only) called just after a traversal has happened.
at_failed_traverse(traversing_object) - (exit-objects only) called if traversal fails and property err_traverse is not defined.
at_msg_receive(self, msg, from_obj=None, data=None) - called when a message (via self.msg()) is sent to this obj.
at_msg_receive(self, msg, from_obj=None, data=None) - called when a message (via self.msg()) is sent to this obj.
If returns false, aborts send.
at_msg_send(self, msg, to_obj=None, data=None) - called when this objects sends a message to someone via self.msg().
at_msg_send(self, msg, to_obj=None, data=None) - called when this objects sends a message to someone via self.msg().
return_appearance(looker) - describes this object. Used by "look" command by default
at_desc(looker=None) - called by 'look' whenever the appearance is requested.
at_desc(looker=None) - called by 'look' whenever the appearance is requested.
at_get(getter) - called after object has been picked up. Does not stop pickup.
at_drop(dropper) - called when this object has been dropped.
at_say(speaker, message) - by default, called if an object inside this object speaks
"""
super(Object, self).__init__(dbobj)
@ -132,84 +132,84 @@ class Object(TypeClass):
def search(self, ostring,
global_search=False,
attribute_name=None,
use_nicks=False,
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.
ostring: (str) The string to match object names against.
Obs - To find a player, append * to the
start of ostring.
start of ostring.
global_search(bool): Search all objects, not just the current
location/inventory
attribute_name (string) Which attribute to match
(if None, uses default 'name')
use_nicks (bool) : Use nickname replace (off by default)
use_nicks (bool) : Use nickname replace (off by default)
location (Object): If None, use caller's current location
ignore_errors (bool): Don't display any error messages even
if there are none/multiple matches -
just return the result as a list.
player (Objectt): Don't search for an Object but a Player.
if there are none/multiple matches -
just return the result as a list.
player (Objectt): Don't search for an Object but a Player.
This will also find players that don't
currently have a character.
Returns - a unique Object/Player match or None. All error
messages are handled by system-commands and the parser-handlers
specified in settings.
specified in settings.
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.
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
syntax for this is 'N-searchword'. So for example, if there
are three objects in the room all named 'ball', you could
address the individual ball as '1-ball', '2-ball', '3-ball'
etc.
etc.
"""
return self.dbobj.search(ostring,
global_search=global_search,
return self.dbobj.search(ostring,
global_search=global_search,
attribute_name=attribute_name,
use_nicks=use_nicks,
location=location,
ignore_errors=ignore_errors,
ignore_errors=ignore_errors,
player=player)
def execute_cmd(self, raw_string):
"""
Do something as this object. This command transparently
lets its typeclass execute the command. Evennia also calls
this method whenever the player sends a command on the command line.
Argument:
Argument:
raw_string (string) - raw command input
Returns Deferred - this is an asynchronous Twisted object that will
not fire until the command has actually finished executing. To overload
this one needs to attach callback functions to it, with addCallback(function).
this one needs to attach callback functions to it, with addCallback(function).
This function will be called with an eventual return value from the command
execution.
execution.
This return is not used at all by Evennia by default, but might be useful
for coders intending to implement some sort of nested command structure.
"""
for coders intending to implement some sort of nested command structure.
"""
return self.dbobj.execute_cmd(raw_string)
def msg(self, message, from_obj=None, data=None):
"""
Emits something to any sessions attached to the object.
message (str): The message to send
from_obj (obj): object that is sending.
data (object): an optional data object that may or may not
be used by the protocol.
be used by the protocol.
"""
self.dbobj.msg(message, from_obj=from_obj, data=data)
@ -228,44 +228,44 @@ class Object(TypeClass):
exit object (i.e. it has "destination"!=None), the move_to will
happen to this destination and -not- into the exit object itself, unless
use_destination=False. Note that no lock checks are done by this function,
such things are assumed to have been handled before calling move_to.
such things are assumed to have been handled before calling move_to.
destination: (Object) Reference to the object to move to. This
can also be an exit object, in which case the destination
property is used as destination.
property is used as destination.
quiet: (bool) If true, don't emit left/arrived messages.
emit_to_obj: (Object) object to receive error messages
use_destination (bool): Default is for objects to use the "destination" property
of destinations as the target to move to. Turning off this
keyword allows objects to move "inside" exit objects.
keyword allows objects to move "inside" exit objects.
Returns True/False depending on if there were problems with the move. This method
may also return various error messages to the emit_to_obj.
may also return various error messages to the emit_to_obj.
"""
return self.dbobj.move_to(destination, quiet=quiet,
emit_to_obj=emit_to_obj, use_destination=use_destination)
def copy(self, new_key=None):
"""
"""
Makes an identical copy of this object. If you want to customize the copy by
changing some settings, use ObjectDB.object.copy_object() directly.
new_key (string) - new key/name of copied object. If new_key is not specified, the copy will be named
<old_key>_copy by default.
Returns: Object (copy of this one)
<old_key>_copy by default.
Returns: Object (copy of this one)
"""
return self.dbobj.copy(new_key=new_key)
def delete(self):
def delete(self):
"""
Deletes this object.
Deletes this object.
Before deletion, this method makes sure to move all contained
objects to their respective home locations, as well as clean
up all exits to/from the object.
Returns: boolean True if deletion succeded, False if there
were errors during deletion or deletion otherwise
failed.
failed.
"""
return self.dbobj.delete()
@ -277,16 +277,16 @@ class Object(TypeClass):
Returns true if this object has this type
OR has a typeclass which is an subclass of
the given typeclass.
typeclass - can be a class object or the
python path to such an object to match against.
python path to such an object to match against.
exact - returns true only if the object's
type is exactly this typeclass, ignoring
parents.
Returns: Boolean
"""
Returns: Boolean
"""
return self.dbobj.is_typeclass(typeclass, exact=exact)
def swap_typeclass(self, new_typeclass, clean_attributes=False, no_default=True):
@ -294,18 +294,18 @@ class Object(TypeClass):
This performs an in-situ swap of the typeclass. This means
that in-game, this object will suddenly be something else.
Player will not be affected. To 'move' a player to a different
object entirely (while retaining this object's type), use
object entirely (while retaining this object's type), use
self.player.swap_object().
Note that this might be an error prone operation if the
Note that this might be an error prone operation if the
old/new typeclass was heavily customized - your code
might expect one and not the other, so be careful to
might expect one and not the other, so be careful to
bug test your code if using this feature! Often its easiest
to create a new object and just swap the player over to
that one instead.
that one instead.
Arguments:
new_typeclass (path/classobj) - type to switch to
Arguments:
new_typeclass (path/classobj) - type to switch to
clean_attributes (bool/list) - will delete all attributes
stored on this object (but not any
of the database fields such as name or
@ -317,10 +317,10 @@ class Object(TypeClass):
no_default - if this is active, the swapper will not allow for
swapping to a default typeclass in case the given
one fails for some reason. Instead the old one
will be preserved.
Returns:
will be preserved.
Returns:
boolean True/False depending on if the swap worked or not.
"""
self.dbobj.swap_typeclass(new_typeclass, clean_attributes=clean_attributes, no_default=no_default)
@ -332,14 +332,14 @@ class Object(TypeClass):
accessing_obj (Object)- object trying to access this one
access_type (string) - type of access sought
default (bool) - what to return if no lock of access_type was found
"""
"""
return self.dbobj.access(accessing_obj, access_type=access_type, default=default)
def check_permstring(self, permstring):
"""
This explicitly checks the given string against this object's
'permissions' property without involving any locks.
permstring (string) - permission string that need to match a permission on the object.
(example: 'Builders')
"""
@ -355,7 +355,7 @@ class Object(TypeClass):
"""
result = self.id == other
if not result and hasattr(other, "id"):
result = self.id == other.id
result = self.id == other.id
if not result:
try:
result = other and self.user.id == other.user.id
@ -366,14 +366,14 @@ class Object(TypeClass):
## hooks called by the game engine
def basetype_setup(self):
"""
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).
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
@ -383,13 +383,13 @@ class Object(TypeClass):
dbref = self.dbobj.dbref
self.locks.add("control:id(%s) or perm(Immortals)" % dbref) # edit locks/permissions, delete
self.locks.add("examine:perm(Builders)") # examine properties
self.locks.add("examine:perm(Builders)") # examine properties
self.locks.add("view:all()") # look at object (visibility)
self.locks.add("edit:perm(Wizards)") # edit properties/attributes
self.locks.add("delete:perm(Wizards)") # delete object
self.locks.add("edit:perm(Wizards)") # edit properties/attributes
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
self.locks.add("puppet:id(%s) or perm(Immortals) or pperm(Immortals)" % dbref) # restricts puppeting of this object
def basetype_posthook_setup(self):
"""
@ -403,27 +403,27 @@ class Object(TypeClass):
def at_object_creation(self):
"""
Called once, when this object is first created.
"""
"""
pass
def at_object_delete(self):
"""
Called just before the database object is
permanently delete()d from the database. If
this method returns False, deletion is aborted.
this method returns False, deletion is aborted.
"""
return True
def at_init(self):
"""
"""
This is always called whenever this object is initiated --
that is, whenever it its typeclass is cached from memory. This
happens on-demand first time the object is used or activated
in some way after being created but also after each server
restart or reload.
"""
pass
pass
def at_cmdset_get(self):
"""
@ -450,7 +450,7 @@ class Object(TypeClass):
"""
Called at the end of the login
process, just before letting
them loose.
them loose.
"""
pass
@ -463,16 +463,16 @@ class Object(TypeClass):
def at_server_reload(self):
"""
This hook is called whenever the server is shutting down for restart/reboot.
This hook is called whenever the server is shutting down for restart/reboot.
If you want to, for example, save non-persistent properties across a restart,
this is the place to do it.
this is the place to do it.
"""
pass
def at_server_shutdown(self):
"""
This hook is called whenever the server is shutting down fully (i.e. not for
a restart).
This hook is called whenever the server is shutting down fully (i.e. not for
a restart).
"""
pass
@ -482,63 +482,63 @@ class Object(TypeClass):
def at_before_move(self, destination):
"""
Called just before starting to move
this object to destination.
this object to destination.
destination - the object we are moving to
If this method returns False/None, the move
is cancelled before it is even started.
is cancelled before it is even started.
"""
#return has_perm(self, destination, "can_move")
return True
return True
def announce_move_from(self, destination):
"""
Called if the move is to be announced. This is
called while we are still standing in the old
location.
location.
destination - the place we are going to.
destination - the place we are going to.
"""
if not self.location:
return
name = self.name
return
name = self.name
loc_name = ""
loc_name = self.location.name
loc_name = self.location.name
dest_name = destination.name
string = "%s is leaving %s, heading for %s."
self.location.msg_contents(string % (name, loc_name, dest_name), exclude=self)
def announce_move_to(self, source_location):
"""
Called after the move if the move was not quiet. At this
point we are standing in the new location.
point we are standing in the new location.
source_location - the place we came from
source_location - the place we came from
"""
name = self.name
name = self.name
if not source_location and self.location.has_player:
# This was created from nowhere and added to a player's
# inventory; it's probably the result of a create command.
string = "You now have %s in your possession." % name
self.location.msg(string)
return
return
src_name = "nowhere"
loc_name = self.location.name
if source_location:
src_name = source_location.name
string = "%s arrives to %s from %s."
string = "%s arrives to %s from %s."
self.location.msg_contents(string % (name, loc_name, src_name), exclude=self)
def at_after_move(self, source_location):
"""
Called after move has completed, regardless of quiet mode or not.
Called after move has completed, regardless of quiet mode or not.
Allows changes to the object due to the location it is now in.
source_location - where we came from
source_location - where we came from
"""
pass
@ -554,92 +554,92 @@ class Object(TypeClass):
def at_object_receive(self, moved_obj, source_location):
"""
Called after an object has been moved into this object.
Called after an object has been moved into this object.
moved_obj - the object moved into this one
source_location - where moved_object came from.
source_location - where moved_object came from.
"""
pass
def at_before_traverse(self, traversing_object):
"""
Called just before an object uses this object to
Called just before an object uses this object to
traverse to another object (i.e. this object is a type of Exit)
The target location should normally be available as self.destination.
"""
pass
def at_after_traverse(self, traversing_object, source_location):
"""
Called just after an object successfully used this object to
Called just after an object successfully used this object to
traverse to another object (i.e. this object is a type of Exit)
The target location should normally be available as self.destination.
"""
pass
def at_failed_traverse(self, traversing_object):
"""
This is called if an object fails to traverse this object for some
This is called if an object fails to traverse this object for some
reason. It will not be called if the attribute err_traverse is defined,
that attribute will then be echoed back instead.
that attribute will then be echoed back instead.
"""
pass
pass
def at_msg_receive(self, msg, from_obj=None, data=None):
"""
This hook is called whenever someone
This hook is called whenever someone
sends a message to this object.
Note that from_obj may be None if the sender did
not include itself as an argument to the obj.msg()
call - so you have to check for this. .
call - so you have to check for this. .
Consider this a pre-processing method before
msg is passed on to the user sesssion. If this
method returns False, the msg will not be
msg is passed on to the user sesssion. If this
method returns False, the msg will not be
passed on.
msg = the message received
from_obj = the one sending the message
"""
return True
return True
def at_msg_send(self, msg, to_obj=None, data=None):
"""
This is a hook that is called when /this/ object
sends a message to another object with obj.msg()
while also specifying that it is the one sending.
while also specifying that it is the one sending.
Note that this method is executed on the object
passed along with the msg() function (i.e. using
obj.msg(msg, caller) will then launch caller.at_msg())
and if no object was passed, it will never be called.
and if no object was passed, it will never be called.
"""
pass
# hooks called by the default cmdset.
# hooks called by the default cmdset.
def return_appearance(self, pobject):
"""
This is a convenient hook for a 'look'
command to call.
command to call.
"""
if not pobject:
return
return
string = "{c%s{n" % self.name
desc = self.attr("desc")
if desc:
string += "\n %s" % desc
exits = []
exits = []
users = []
things = []
for content in [con for con in self.contents if con.access(pobject, 'view')]:
if content == pobject:
continue
continue
name = content.name
if content.destination:
exits.append(name)
@ -651,17 +651,17 @@ class Object(TypeClass):
string += "\n{wExits:{n " + ", ".join(exits)
if users or things:
string += "\n{wYou see: {n"
if users:
if users:
string += "{c" + ", ".join(users) + "{n "
if things:
string += ", ".join(things)
if things:
string += ", ".join(things)
return string
def at_desc(self, looker=None):
"""
This is called whenever someone looks
at this object. Looker is the looking
object.
object.
"""
pass
@ -685,8 +685,8 @@ class Object(TypeClass):
def at_say(self, speaker, message):
"""
Called on this object if an object inside this object speaks.
The string returned from this method is the final form
of the speech. Obs - you don't have to add things like
The string returned from this method is the final form
of the speech. Obs - you don't have to add things like
'you say: ' or similar, that is handled by the say command.
speaker - the object speaking
@ -695,7 +695,7 @@ class Object(TypeClass):
return message
#
# Base Player object
# Base Player object
#
class Character(Object):
@ -703,24 +703,24 @@ class Character(Object):
This is just like the Object except it implements its own
version of the at_object_creation to set up the script
that adds the default cmdset to the 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).
overload the defaults (it is called after this one).
"""
super(Character, self).basetype_setup()
self.locks.add("get:false()") # noone can pick up the character
self.locks.add("call:false()") # no commands can be called on character from outside
self.locks.add("call:false()") # no commands can be called on character from outside
# add the default cmdset
from settings import CMDSET_DEFAULT
from settings import CMDSET_DEFAULT
self.cmdset.add_default(CMDSET_DEFAULT, permanent=True)
# no other character should be able to call commands on the Character.
self.cmdset.outside_access = False
# no other character should be able to call commands on the Character.
self.cmdset.outside_access = False
def at_object_creation(self):
"""
@ -728,8 +728,8 @@ class Character(Object):
the script is permanently stored to this object (the permanent
keyword creates a script to do this), we should never need to
do this again for as long as this object exists.
"""
pass
"""
pass
def at_after_move(self, source_location):
"Default is to look around after a move."
@ -737,34 +737,34 @@ class Character(Object):
def at_disconnect(self):
"""
We stove away the character when logging off, otherwise the character object will
We stove away the character when logging off, otherwise the character object will
remain in the room also after the player logged off ("headless", so to say).
"""
if self.location: # have to check, in case of multiple connections closing
if self.location: # have to check, in case of multiple connections closing
self.location.msg_contents("%s has left the game." % self.name, exclude=[self])
self.db.prelogout_location = self.location
self.location = None
self.location = None
def at_post_login(self):
"""
This recovers the character again after having been "stoved away" at disconnect.
"""
if self.db.prelogout_location:
# try to recover
self.location = self.db.prelogout_location
# try to recover
self.location = self.db.prelogout_location
if self.location == None:
# make sure location is never None (home should always exist)
self.location = self.home
# save location again to be sure
# save location again to be sure
self.db.prelogout_location = self.location
self.location.msg_contents("%s has entered the game." % self.name, exclude=[self])
self.location.at_object_receive(self, self.location)
#
# Base Room object
# Base Room object
#
class Room(Object):
@ -778,16 +778,16 @@ class Room(Object):
(since default is None anyway)
Don't change this, instead edit at_object_creation() to
overload the defaults (it is called after this one).
overload the defaults (it is called after this one).
"""
super(Room, self).basetype_setup()
self.locks.add("get:false();puppet:false()") # would be weird to puppet a room ...
self.location = None
self.location = None
#
# Exits
# Exits
#
class Exit(Object):
@ -795,16 +795,16 @@ class Exit(Object):
This is the base exit object - it connects a location to
another. This is done by the exit assigning a "command" on itself
with the same name as the exit object (to do this we need to
remember to re-create the command when the object is cached since it must be
remember to re-create the command when the object is cached since it must be
created dynamically depending on what the exit is called). This
command (which has a high priority) will thus allow us to traverse exits
simply by giving the exit-object's name on its own.
"""
"""
# Helper classes and methods to implement the Exit. These need not
# be overloaded unless one want to change the foundation for how
# Exits work. See the end of the class for hook methods to overload.
# Exits work. See the end of the class for hook methods to overload.
def create_exit_cmdset(self, exidbobj):
"""
@ -812,8 +812,8 @@ class Exit(Object):
The command of this cmdset has the same name as the Exit object
and allows the exit to react when the player enter the exit's name,
triggering the movement between rooms.
triggering the movement between rooms.
Note that exitdbobj is an ObjectDB instance. This is necessary
for handling reloads and avoid tracebacks if this is called while
the typeclass system is rebooting.
@ -821,9 +821,9 @@ class Exit(Object):
class ExitCommand(command.Command):
"""
This is a command that simply cause the caller
to traverse the object it is attached to.
to traverse the object it is attached to.
"""
locks = "cmd:all()" # should always be set to this.
locks = "cmd:all()" # should always be set to this.
obj = None
arg_regex=r"\s.*?|$"
@ -831,15 +831,15 @@ class Exit(Object):
"Default exit traverse if no syscommand is defined."
if self.obj.access(self.caller, 'traverse'):
# we may traverse the exit.
# we may traverse the exit.
old_location = None
old_location = None
if hasattr(self.caller, "location"):
old_location = self.caller.location
old_location = self.caller.location
# call pre/post hooks and move object.
self.obj.at_before_traverse(self.caller)
self.caller.move_to(self.obj.destination)
self.caller.move_to(self.obj.destination)
self.obj.at_after_traverse(self.caller, old_location)
else:
@ -853,7 +853,7 @@ class Exit(Object):
# create an exit command.
cmd = ExitCommand()
cmd.key = exidbobj.db_key.strip().lower()
cmd.obj = exidbobj
cmd.obj = exidbobj
cmd.aliases = exidbobj.aliases
cmd.locks = str(exidbobj.locks)
cmd.destination = exidbobj.db_destination
@ -861,18 +861,18 @@ class Exit(Object):
exit_cmdset = cmdset.CmdSet(None)
exit_cmdset.key = '_exitset'
exit_cmdset.priority = 9
exit_cmdset.duplicates = True
# add command to cmdset
exit_cmdset.add(cmd)
exit_cmdset.duplicates = True
# add command to cmdset
exit_cmdset.add(cmd)
return exit_cmdset
# Command hooks
# Command hooks
def basetype_setup(self):
"""
Setup exit-security
Don't change this, instead edit at_object_creation() to
overload the default locks (it is called after this one).
overload the default locks (it is called after this one).
"""
super(Exit, self).basetype_setup()
@ -880,34 +880,34 @@ class Exit(Object):
self.locks.add("puppet:false()") # would be weird to puppet an exit ...
self.locks.add("traverse:all()") # who can pass through exit by default
self.locks.add("get:false()") # noone can pick up the exit
# an exit should have a destination (this is replaced at creation time)
if self.dbobj.location:
self.destination = self.dbobj.location
self.destination = self.dbobj.location
def at_cmdset_get(self):
"""
Called when the cmdset is requested from this object, just before the cmdset is
Called when the cmdset is requested from this object, just before the cmdset is
actually extracted. If no Exit-cmdset is cached, create it now.
"""
"""
if self.ndb.exit_reset or not self.cmdset.has_cmdset("_exitset", must_be_default=True):
# we are resetting, or no exit-cmdset was set. Create one dynamically.
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
self.ndb.exit_reset = False
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
self.ndb.exit_reset = False
# this and other hooks are what usually can be modified safely.
# this and other hooks are what usually can be modified safely.
def at_object_creation(self):
"Called once, when object is first created (after basetype_setup)."
pass
pass
def at_failed_traverse(self, traversing_object):
"""
This is called if an object fails to traverse this object for some
This is called if an object fails to traverse this object for some
reason. It will not be called if the attribute "err_traverse" is defined,
that attribute will then be echoed back instead as a convenient shortcut.
that attribute will then be echoed back instead as a convenient shortcut.
(See also hooks at_before_traverse and at_after_traverse).
(See also hooks at_before_traverse and at_after_traverse).
"""
traversing_object.msg("You cannot go there.")

View file

@ -19,7 +19,7 @@ try:
from django.utils.unittest import TestCase
except ImportError:
from django.test import TestCase
try:
try:
from django.utils import unittest
except ImportError:
import unittest
@ -47,10 +47,10 @@ class TestObjAttrs(TestCase):
self.obj1.db.testattr = self.obj2
self.assertEqual(self.obj2 ,self.obj1.db.testattr)
self.assertEqual(self.obj2.location, self.obj1.db.testattr.location)
def suite():
"""
This function is called automatically by the django test runner.
This function is called automatically by the django test runner.
This also runs the command tests defined in src/commands/default/tests.py.
"""
tsuite = unittest.TestSuite()