mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 09:46:32 +01:00
Fixed some bugs in the access system. Changed the "owner" default permission to "control" instead to more general. Added a new hook for setting locks for objects (the suspicion was that this would give lots of grief to newbies otherwise, now we have a lockdown policy in the absence of lock definitions).
This commit is contained in:
parent
295a82cc04
commit
bccd84e480
12 changed files with 115 additions and 124 deletions
|
|
@ -43,6 +43,13 @@ class Object(BaseObject):
|
|||
of Evennia and messing with them might well break things for you.
|
||||
|
||||
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.
|
||||
|
|
@ -100,14 +107,7 @@ class Character(BaseCharacter):
|
|||
command set whenever the player logs in - otherwise they won't be
|
||||
able to use any commands!
|
||||
"""
|
||||
def at_object_creation(self):
|
||||
# This adds the default cmdset to the player every time they log
|
||||
# in. Don't change this unless you really know what you are doing.
|
||||
super(Character, self).at_object_creation()
|
||||
|
||||
# expand with whatever customizations you want below...
|
||||
# ...
|
||||
|
||||
|
||||
def at_disconnect(self):
|
||||
"""
|
||||
We stove away the character when logging off, otherwise they will remain where
|
||||
|
|
@ -145,23 +145,19 @@ class Exit(BaseExit):
|
|||
hard-coded in their typeclass. Exits do have to make sure they
|
||||
clean up a bit after themselves though, easiest accomplished
|
||||
by letting by_object_delete() call the object's parent.
|
||||
"""
|
||||
|
||||
def at_object_delete(self):
|
||||
"""
|
||||
The game needs to do some cache cleanups when deleting an exit,
|
||||
so we make sure to call super() here. If this method returns
|
||||
False, the deletion is aborted.
|
||||
"""
|
||||
# handle some cleanups
|
||||
return super(Exit, self).at_object_delete()
|
||||
# custom modifications below.
|
||||
# ...
|
||||
Note that exits need to do cache-cleanups after they are
|
||||
deleted, so if you re-implement at_object_delete() for some
|
||||
reason, make sure to call the parent class-method too!
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
class Player(BasePlayer):
|
||||
"""
|
||||
This class describes the actual OOC player (i.e. the user connecting
|
||||
to the MUD). It does NOT have visual appearance in the game world (that
|
||||
|
||||
is handled by the character which is connected to this). Comm channels
|
||||
are attended/joined using this object.
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class CmdBoot(MuxCommand):
|
|||
"""
|
||||
|
||||
key = "@boot"
|
||||
locks = "cmd:perm(boot) or perm(Wizard)"
|
||||
locks = "cmd:perm(boot) or perm(Wizards)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -315,17 +315,13 @@ class CmdPerm(MuxCommand):
|
|||
@perm - set permissions
|
||||
|
||||
Usage:
|
||||
@perm[/switch] [<object>] = [<permission>]
|
||||
@perm[/switch] [*<player>] = [<permission>]
|
||||
|
||||
@perm[/switch] <object> [= <permission>[,<permission>,...]]
|
||||
|
||||
Switches:
|
||||
del : delete the given permission from <object>.
|
||||
list : list all permissions, or those set on <object>
|
||||
|
||||
Use * before the search string to add permissions to a player.
|
||||
This command sets/clears individual permission strings on an object.
|
||||
Use /list without any arguments to see all available permissions
|
||||
or those defined on the <object>/<player> argument.
|
||||
If no permission is given, list all permissions on <object>
|
||||
"""
|
||||
key = "@perm"
|
||||
aliases = "@setperm"
|
||||
|
|
@ -339,52 +335,39 @@ class CmdPerm(MuxCommand):
|
|||
switches = self.switches
|
||||
lhs, rhs = self.lhs, self.rhs
|
||||
|
||||
if not self.args:
|
||||
|
||||
if "list" not in switches:
|
||||
string = "Usage: @setperm[/switch] [object = permission]\n"
|
||||
string += " @setperm[/switch] [*player = permission]"
|
||||
caller.msg(string)
|
||||
return
|
||||
else:
|
||||
#just print all available permissions
|
||||
string = "\nAll defined permission groups and keys (i.e. not locks):"
|
||||
pgroups = list(PermissionGroup.objects.all())
|
||||
pgroups.sort(lambda x, y: cmp(x.key, y.key)) # sort by group key
|
||||
if not self.args:
|
||||
string = "Usage: @perm[/switch] object [ = permission, permission, ...]\n"
|
||||
caller.msg(string)
|
||||
return
|
||||
|
||||
for pgroup in pgroups:
|
||||
string += "\n\n - {w%s{n (%s):" % (pgroup.key, pgroup.desc)
|
||||
string += "\n%s" % \
|
||||
utils.fill(", ".join(sorted(pgroup.group_permissions)))
|
||||
caller.msg(string)
|
||||
return
|
||||
|
||||
# locate the object/player
|
||||
# locate the object
|
||||
obj = caller.search(lhs, global_search=True)
|
||||
if not obj:
|
||||
return
|
||||
|
||||
pstring = ""
|
||||
if utils.inherits_from(obj, settings.BASE_PLAYER_TYPECLASS):
|
||||
pstring = " Player "
|
||||
|
||||
|
||||
if not rhs:
|
||||
string = "Permission string on %s{w%s{n: " % (pstring, obj.key)
|
||||
|
||||
if not obj.access(caller, 'examine'):
|
||||
caller.msg("You are not allowed to examine this object.")
|
||||
return
|
||||
|
||||
string = "Permissions on {w%s{n: " % obj.key
|
||||
if not obj.permissions:
|
||||
string += "<None>"
|
||||
else:
|
||||
string += ", ".join(obj.permissions)
|
||||
if pstring and obj.is_superuser:
|
||||
string += "\n(... But this player is a SUPERUSER! "
|
||||
string += "All access checked are passed automatically.)"
|
||||
elif obj.player and obj.player.is_superuser:
|
||||
string += "\n(... But this object's player is a SUPERUSER! "
|
||||
string += "All access checked are passed automatically.)"
|
||||
if hasattr(obj, 'player') and hasattr(obj.player, 'is_superuser') and obj.player.is_superuser:
|
||||
string += "\n(... but this object is currently controlled by a SUPERUSER! "
|
||||
string += "All access checks are passed automatically.)"
|
||||
caller.msg(string)
|
||||
return
|
||||
|
||||
# we supplied an argument on the form obj = perm
|
||||
|
||||
if not obj.access(caller, 'control'):
|
||||
caller.msg("You are not allowed to edit this object's permissions.")
|
||||
return
|
||||
|
||||
cstring = ""
|
||||
tstring = ""
|
||||
if 'del' in switches:
|
||||
|
|
@ -393,26 +376,24 @@ class CmdPerm(MuxCommand):
|
|||
try:
|
||||
index = obj.permissions.index(perm)
|
||||
except ValueError:
|
||||
cstring += "\nPermission '%s' was not defined on %s%s." % (perm, pstring, lhs)
|
||||
cstring += "\nPermission '%s' was not defined on %s." % (perm, obj.name)
|
||||
continue
|
||||
permissions = obj.permissions
|
||||
del permissions[index]
|
||||
obj.permissions = permissions
|
||||
cstring += "\nPermission '%s' was removed from %s%s." % (perm, pstring, obj.name)
|
||||
cstring += "\nPermission '%s' was removed from %s." % (perm, obj.name)
|
||||
tstring += "\n%s revokes the permission '%s' from you." % (caller.name, perm)
|
||||
else:
|
||||
# As an extra check, we warn the user if they customize the
|
||||
# permission string (which is okay, and is used by the lock system)
|
||||
# add a new permission
|
||||
permissions = obj.permissions
|
||||
for perm in self.rhslist:
|
||||
|
||||
if perm in permissions:
|
||||
cstring += "\nPermission '%s' is already defined on %s%s." % (rhs, pstring, obj.name)
|
||||
cstring += "\nPermission '%s' is already defined on %s%s." % (rhs, obj.name)
|
||||
else:
|
||||
permissions.append(perm)
|
||||
obj.permissions = permissions
|
||||
cstring += "\nPermission '%s' given to %s%s." % (rhs, pstring, obj.name)
|
||||
tstring += "\n%s granted you the permission '%s'." % (caller.name, rhs)
|
||||
cstring += "\nPermission '%s' given to %s." % (rhs, obj.name)
|
||||
tstring += "\n%s gives you the permission '%s'." % (caller.name, rhs)
|
||||
caller.msg(cstring.strip())
|
||||
if tstring:
|
||||
obj.msg(tstring.strip())
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ class CmdBatchCommands(MuxCommand):
|
|||
"""
|
||||
key = "@batchcommands"
|
||||
aliases = ["@batchcommand", "@batchcmd"]
|
||||
locks = "cmd:perm(batchcommands)"
|
||||
locks = "cmd:perm(batchcommands) or superuser()"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -277,7 +277,7 @@ class CmdBatchCode(MuxCommand):
|
|||
"""
|
||||
key = "@batchcode"
|
||||
aliases = ["@batchcodes"]
|
||||
locks = "cmd:perm(batchcommands)"
|
||||
locks = "cmd:perm(batchcommands) or superuser()"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
|
|||
|
|
@ -1299,7 +1299,7 @@ class CmdLock(ObjManipCommand):
|
|||
if lockdef:
|
||||
string = lockdef[2]
|
||||
if 'del' in self.switches:
|
||||
if not obj.access(caller, 'edit'):
|
||||
if not obj.access(caller, 'control'):
|
||||
caller.msg("You are not allowed to do that.")
|
||||
return
|
||||
obj.locks.delete(access_type)
|
||||
|
|
@ -1315,7 +1315,7 @@ class CmdLock(ObjManipCommand):
|
|||
obj = caller.search(objname)
|
||||
if not obj:
|
||||
return
|
||||
if not obj.access(caller, 'edit'):
|
||||
if not obj.access(caller, 'control'):
|
||||
caller.msg("You are not allowed to do that.")
|
||||
return
|
||||
ok = obj.locks.add(lockdef, caller)
|
||||
|
|
@ -1452,7 +1452,7 @@ class CmdExamine(ObjManipCommand):
|
|||
obj = caller.location
|
||||
if not obj.access(caller, 'examine'):
|
||||
#If we don't have special info access, just look at the object instead.
|
||||
caller.exec_cmd('look %s' % obj.name)
|
||||
caller.execute_cmd('look %s' % obj.name)
|
||||
return
|
||||
string = self.format_output(obj)
|
||||
|
||||
|
|
@ -1471,7 +1471,7 @@ class CmdExamine(ObjManipCommand):
|
|||
continue
|
||||
if not obj.access(caller, 'examine'):
|
||||
#If we don't have special info access, just look at the object instead.
|
||||
caller.exec_cmd('look %s' % obj_name)
|
||||
caller.execute_cmd('look %s' % obj_name)
|
||||
continue
|
||||
if obj_attrs:
|
||||
for attrname in obj_attrs:
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ from django.contrib import admin
|
|||
from src.comms.models import Channel, Msg, ChannelConnection
|
||||
|
||||
class MsgAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message')
|
||||
list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message', 'db_lock_storage')
|
||||
list_display_links = ("id",)
|
||||
ordering = ["db_date_sent", 'db_sender', 'db_receivers', 'db_channels']
|
||||
readonly_fields = ['db_permissions', 'db_message', 'db_sender', 'db_receivers', 'db_channels']
|
||||
readonly_fields = ['db_message', 'db_sender', 'db_receivers', 'db_channels']
|
||||
search_fields = ['id', '^db_date_sent', '^db_message']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
@ -18,23 +18,22 @@ class MsgAdmin(admin.ModelAdmin):
|
|||
admin.site.register(Msg, MsgAdmin)
|
||||
|
||||
class ChannelAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_key', 'db_desc', 'db_aliases', 'db_keep_log', 'db_permissions')
|
||||
list_display = ('id', 'db_key', 'db_desc', 'db_aliases', 'db_keep_log', 'db_lock_storage')
|
||||
list_display_links = ("id", 'db_key')
|
||||
ordering = ["db_key"]
|
||||
readonly_fields = ['db_permissions']
|
||||
search_fields = ['id', 'db_key', 'db_aliases']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
admin.site.register(Channel, ChannelAdmin)
|
||||
|
||||
class ChannelConnectionAdmin(admin.ModelAdmin):
|
||||
list_display = ('db_channel', 'db_player')
|
||||
list_display_links = ("db_player", 'db_channel')
|
||||
ordering = ["db_channel"]
|
||||
search_fields = ['db_channel', 'db_player']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
admin.site.register(ChannelConnection, ChannelConnectionAdmin)
|
||||
# class ChannelConnectionAdmin(admin.ModelAdmin):
|
||||
# list_display = ('db_channel', 'db_player')
|
||||
# list_display_links = ("db_player", 'db_channel')
|
||||
# ordering = ["db_channel"]
|
||||
# search_fields = ['db_channel', 'db_player']
|
||||
# save_as = True
|
||||
# save_on_top = True
|
||||
# list_select_related = True
|
||||
# admin.site.register(ChannelConnection, ChannelConnectionAdmin)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from django.contrib import admin
|
|||
from src.help.models import HelpEntry
|
||||
|
||||
class HelpEntryAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_key', 'db_help_category', 'db_permissions')
|
||||
list_display = ('id', 'db_key', 'db_help_category')
|
||||
list_display_links = ('id', 'db_key')
|
||||
search_fields = ['^db_key', 'db_entrytext']
|
||||
ordering = ['db_help_category', 'db_key']
|
||||
|
|
|
|||
|
|
@ -348,12 +348,13 @@ def test():
|
|||
obj1 = TestObj()
|
||||
obj2 = TestObj()
|
||||
|
||||
obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Wizards);examine:perm(Builders);delete:perm(Wizards);get:all()"
|
||||
#obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Wizards);examine:perm(Builders);delete:perm(Wizards);get:all()"
|
||||
#obj1.lock_storage = "cmd:all();admin:id(1);listen:all();send:all()"
|
||||
obj1.lock_storage = "listen:perm(Immortals)"
|
||||
|
||||
pdb.set_trace()
|
||||
obj1.locks = LockHandler(obj1)
|
||||
obj2.permissions = ["Wizards"]
|
||||
obj2.permissions = ["Immortals"]
|
||||
obj2.id = 4
|
||||
|
||||
#obj1.locks.add("edit:attr(test)")
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@ from src.objects.models import ObjAttribute, ObjectDB
|
|||
from django.contrib import admin
|
||||
|
||||
class ObjAttributeAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_key', 'db_value', 'db_mode', 'db_obj', 'db_permissions')
|
||||
list_display = ('id', 'db_key', 'db_value', 'db_mode', 'db_obj')
|
||||
list_display_links = ("id", 'db_key')
|
||||
ordering = ["db_obj", 'db_key']
|
||||
readonly_fields = ['db_permissions']
|
||||
search_fields = ['id', 'db_key', 'db_obj']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
@ -21,7 +20,7 @@ class ObjectDBAdmin(admin.ModelAdmin):
|
|||
list_display = ('id', 'db_key', 'db_typeclass_path', 'db_location', 'db_player')
|
||||
list_display_links = ('id', 'db_key')
|
||||
ordering = ['id', 'db_typeclass_path']
|
||||
readonly_fields = ['db_permissions']
|
||||
readonly_fields = ['db_permissions', 'db_lock_storage']
|
||||
search_fields = ['^db_key', 'db_typeclass_path']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
|
|||
|
|
@ -75,22 +75,30 @@ 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.
|
||||
"""
|
||||
# the default security setup fallback for a generic
|
||||
# object. Overload in child for a custom setup. Also creation
|
||||
# commands may set this (create an item and you should be its
|
||||
# controller, for example)
|
||||
|
||||
dbref = self.dbobj.dbref
|
||||
|
||||
self.locks.add("control:id(%s)" % dbref)
|
||||
self.locks.add("examine:perm(Builders)")
|
||||
self.locks.add("edit:perm(Wizards)")
|
||||
self.locks.add("delete:perm(Wizards)")
|
||||
self.locks.add("get:all()")
|
||||
|
||||
def at_object_creation(self):
|
||||
"""
|
||||
Called once, when this object is first
|
||||
created.
|
||||
"""
|
||||
|
||||
# the default security setup fallback for a generic
|
||||
# object. Overload in child for a custom setup. Also creation
|
||||
# commands may set this (create an item and you should its
|
||||
# owner, for example)
|
||||
dbref = self.dbobj.dbref
|
||||
self.locks.add("owner:id(%s)" % dbref)
|
||||
self.locks.add("examine:perm(Builders)")
|
||||
self.locks.add("edit:perm(Wizards)")
|
||||
self.locks.add("delete:perm(Wizards)")
|
||||
self.locks.add("get:all()")
|
||||
pass
|
||||
|
||||
def at_first_login(self):
|
||||
"""
|
||||
|
|
@ -327,25 +335,31 @@ class Character(Object):
|
|||
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
|
||||
"""
|
||||
super(Character, self).basetype_setup()
|
||||
self.locks.add("puppet:id(%s) or perm(Immortals)" % self.dbobj.dbref)
|
||||
|
||||
# add the default cmdset
|
||||
from settings import CMDSET_DEFAULT
|
||||
self.cmdset.add_default(CMDSET_DEFAULT, permanent=True)
|
||||
|
||||
def at_object_creation(self):
|
||||
"""
|
||||
All this does (for now) is to add the default cmdset. Since
|
||||
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
|
||||
"""
|
||||
from settings import CMDSET_DEFAULT
|
||||
self.cmdset.add_default(CMDSET_DEFAULT, permanent=True)
|
||||
|
||||
# setup security
|
||||
super(Character, self).at_object_creation()
|
||||
self.locks.add("puppet:id(%s) or perm(Immortals)" % self.dbobj.dbref)
|
||||
|
||||
def at_after_move(self, source_location):
|
||||
"Default is to look around after a move."
|
||||
self.execute_cmd('look')
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Base Room object
|
||||
#
|
||||
|
|
@ -355,12 +369,12 @@ class Room(Object):
|
|||
This is the base room object. It's basically
|
||||
like any Object except its location is None.
|
||||
"""
|
||||
def at_object_creation(self):
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
Simple setup, shown as an example
|
||||
(since default is None anyway)
|
||||
"""
|
||||
super(Room, self).at_object_creation()
|
||||
super(Room, self).basetype_setup()
|
||||
self.location = None
|
||||
|
||||
class Exit(Object):
|
||||
|
|
@ -375,6 +389,14 @@ class Exit(Object):
|
|||
the attribute _destination to a valid location
|
||||
('Quack like a duck...' and so forth).
|
||||
"""
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
Setup exit-security
|
||||
"""
|
||||
# the lock is open to all by default
|
||||
super(Exit, self).basetype_setup()
|
||||
self.locks.add("traverse:all()")
|
||||
|
||||
def at_object_creation(self):
|
||||
"""
|
||||
Another example just for show; the _destination attribute
|
||||
|
|
@ -385,10 +407,6 @@ class Exit(Object):
|
|||
# this is what makes it an exit
|
||||
self.attr("_destination", "None")
|
||||
|
||||
# the lock is open to all by default
|
||||
super(Exit, self).at_object_creation()
|
||||
self.locks.add("traverse:all()")
|
||||
|
||||
def at_object_delete(self):
|
||||
"""
|
||||
We have to make sure to clean the exithandler cache
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@ from src.players.models import PlayerDB, PlayerAttribute
|
|||
from django.contrib import admin
|
||||
|
||||
class PlayerAttributeAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_key', 'db_value', 'db_mode', 'db_obj', 'db_permissions')
|
||||
list_display = ('id', 'db_key', 'db_value', 'db_mode', 'db_obj')
|
||||
list_display_links = ("id", 'db_key')
|
||||
ordering = ["db_obj", 'db_key']
|
||||
readonly_fields = ['db_permissions']
|
||||
search_fields = ['id', 'db_key', 'db_obj']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
@ -21,7 +20,6 @@ class PlayerDBAdmin(admin.ModelAdmin):
|
|||
list_display = ('id', 'user', 'db_obj', 'db_typeclass_path')
|
||||
list_display_links = ('id', 'user')
|
||||
ordering = ['id', 'user']
|
||||
readonly_fields = ['db_permissions']
|
||||
search_fields = ['^db_key', 'db_typeclass_path']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@ from src.scripts.models import ScriptAttribute, ScriptDB
|
|||
from django.contrib import admin
|
||||
|
||||
class ScriptAttributeAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_key', 'db_value', 'db_mode', 'db_obj', 'db_permissions')
|
||||
list_display = ('id', 'db_key', 'db_value', 'db_mode', 'db_obj')
|
||||
list_display_links = ("id", 'db_key')
|
||||
ordering = ["db_obj", 'db_key']
|
||||
readonly_fields = ['db_permissions']
|
||||
search_fields = ['id', 'db_key', 'db_obj']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
@ -20,8 +19,7 @@ admin.site.register(ScriptAttribute, ScriptAttributeAdmin)
|
|||
class ScriptDBAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'db_key', 'db_typeclass_path', 'db_obj', 'db_interval', 'db_repeats', 'db_persistent')
|
||||
list_display_links = ('id', 'db_key')
|
||||
ordering = ['db_obj', 'db_typeclass_path']
|
||||
readonly_fields = ['db_permissions']
|
||||
ordering = ['db_obj', 'db_typeclass_path']
|
||||
search_fields = ['^db_key', 'db_typeclass_path']
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ def create_object(typeclass, key=None, location=None,
|
|||
# call the hook method. This is where all at_creation
|
||||
# customization happens as the typeclass stores custom
|
||||
# things on its database object.
|
||||
new_object.basetype_setup() # setup the basics of Exits, Characters etc.
|
||||
new_object.at_object_creation()
|
||||
|
||||
# custom-given variables override the hook
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue