Example #1
0
 def update_defaults(self):
     """
     We make sure to store the most important object defaults here, so we can catch if they
     change and update them on-objects automatically. This allows for changing default cmdset locations
     and default typeclasses in the settings file and have them auto-update all already existing
     objects.
     """
     # setting names
     settings_names = ("CMDSET_DEFAULT", "CMDSET_OOC", "BASE_PLAYER_TYPECLASS", "BASE_OBJECT_TYPECLASS",
                       "BASE_CHARACTER_TYPECLASS", "BASE_ROOM_TYPECLASS", "BASE_EXIT_TYPECLASS", "BASE_SCRIPT_TYPECLASS")
     # get previous and current settings so they can be compared
     settings_compare = zip([ServerConfig.objects.conf(name) for name in settings_names],
                            [settings.__getattr__(name) for name in settings_names])
     mismatches = [i for i, tup in enumerate(settings_compare) if tup[0] and tup[1] and tup[0] != tup[1]]
     if len(mismatches): # can't use any() since mismatches may be [0] which reads as False for any()
         # we have a changed default. Import relevant objects and run the update
         from src.objects.models import ObjectDB
         #from src.players.models import PlayerDB
         for i, prev, curr in ((i, tup[0], tup[1]) for i, tup in enumerate(settings_compare) if i in mismatches):
             # update the database
             print " one or more default cmdset/typeclass settings changed. Updating defaults stored in database ..."
             if i == 0: [obj.__setattr__("cmdset_storage", curr) for obj in ObjectDB.objects.filter(db_cmdset_storage__exact=prev)]
             if i == 1: [ply.__setattr__("cmdset_storage", curr) for ply in PlayerDB.objects.filter(db_cmdset_storage__exact=prev)]
             if i == 2: [ply.__setattr__("typeclass_path", curr) for ply in PlayerDB.objects.filter(db_typeclass_path__exact=prev)]
             if i in (3,4,5,6): [obj.__setattr__("typeclass_path",curr)
                                 for obj in ObjectDB.objects.filter(db_typeclass_path__exact=prev)]
             if i == 7: [scr.__setattr__("typeclass_path", curr) for scr in ScriptDB.objects.filter(db_typeclass_path__exact=prev)]
             # store the new default and clean caches
             ServerConfig.objects.conf(settings_names[i], curr)
             ObjectDB.flush_instance_cache()
             PlayerDB.flush_instance_cache()
             ScriptDB.flush_instance_cache()
     # if this is the first start we might not have a "previous" setup saved. Store it now.
     [ServerConfig.objects.conf(settings_names[i], tup[1]) for i, tup in enumerate(settings_compare) if not tup[0]]
Example #2
0
def make_exit(item):
    """
    We'll do special stuff with these later.
    """
    aliases = item["name"].split(';')
    name = aliases[0]
    aliases = aliases[1:]
    thing = ObjectDB(name=name)
    thing.aliases.add(aliases)
    thing.save()
Example #3
0
 def update_defaults(self):
     """
     We make sure to store the most important object defaults here, so
     we can catch if they change and update them on-objects automatically.
     This allows for changing default cmdset locations and default
     typeclasses in the settings file and have them auto-update all
     already existing objects.
     """
     # setting names
     settings_names = ("CMDSET_CHARACTER", "CMDSET_PLAYER",
                       "BASE_PLAYER_TYPECLASS", "BASE_OBJECT_TYPECLASS",
                       "BASE_CHARACTER_TYPECLASS", "BASE_ROOM_TYPECLASS",
                       "BASE_EXIT_TYPECLASS", "BASE_SCRIPT_TYPECLASS",
                       "BASE_CHANNEL_TYPECLASS")
     # get previous and current settings so they can be compared
     settings_compare = zip([ServerConfig.objects.conf(name) for name in settings_names],
                            [settings.__getattr__(name) for name in settings_names])
     mismatches = [i for i, tup in enumerate(settings_compare) if tup[0] and tup[1] and tup[0] != tup[1]]
     if len(mismatches):  # can't use any() since mismatches may be [0] which reads as False for any()
         # we have a changed default. Import relevant objects and
         # run the update
         from src.objects.models import ObjectDB
         from src.comms.models import ChannelDB
         #from src.players.models import PlayerDB
         for i, prev, curr in ((i, tup[0], tup[1]) for i, tup in enumerate(settings_compare) if i in mismatches):
             # update the database
             print " %s:\n '%s' changed to '%s'. Updating unchanged entries in database ..." % (settings_names[i], prev, curr)
             if i == 0:
                 [obj.__setattr__("cmdset_storage", curr) for obj in ObjectDB.objects.filter(db_cmdset_storage__exact=prev)]
             if i == 1:
                 [ply.__setattr__("cmdset_storage", curr) for ply in PlayerDB.objects.filter(db_cmdset_storage__exact=prev)]
             if i == 2:
                 [ply.__setattr__("typeclass_path", curr) for ply in PlayerDB.objects.filter(db_typeclass_path__exact=prev)]
             if i in (3, 4, 5, 6):
                 [obj.__setattr__("typeclass_path", curr) for obj in ObjectDB.objects.filter(db_typeclass_path__exact=prev)]
             if i == 7:
                 [scr.__setattr__("typeclass_path", curr) for scr in ScriptDB.objects.filter(db_typeclass_path__exact=prev)]
             if i == 8:
                 [scr.__setattr__("typeclass_path", curr) for scr in ChannelDB.objects.filter(db_typeclass_path__exact=prev)]
             # store the new default and clean caches
             ServerConfig.objects.conf(settings_names[i], curr)
             ObjectDB.flush_instance_cache()
             PlayerDB.flush_instance_cache()
             ScriptDB.flush_instance_cache()
             ChannelDB.flush_instance_cache()
     # if this is the first start we might not have a "previous"
     # setup saved. Store it now.
     [ServerConfig.objects.conf(settings_names[i], tup[1])
                     for i, tup in enumerate(settings_compare) if not tup[0]]
Example #4
0
    def run_init_hooks(self):
        """
        Called every server start
        """
        from src.objects.models import ObjectDB
        #from src.players.models import PlayerDB

        #update eventual changed defaults
        self.update_defaults()

        #print "run_init_hooks:", ObjectDB.get_all_cached_instances()
        [(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()]
        [(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()]

        if SERVER_STARTSTOP_MODULE:
            # call correct server hook based on start file value
            with open(SERVER_RESTART, 'r') as f:
                mode = f.read()
            if mode in ('True', 'reload'):
                # True was the old reload flag, kept for compatibilty
                SERVER_STARTSTOP_MODULE.at_server_reload_start()
            elif mode in ('reset', 'shutdown'):
                SERVER_STARTSTOP_MODULE.at_server_cold_start()
            # always call this regardless of start type
            SERVER_STARTSTOP_MODULE.at_server_start()
Example #5
0
    def run_init_hooks(self):
        """
        Called every server start
        """
        from src.objects.models import ObjectDB
        #from src.players.models import PlayerDB

        #update eventual changed defaults
        self.update_defaults()

        #print "run_init_hooks:", ObjectDB.get_all_cached_instances()
        [(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()]
        [(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()]

        with open(SERVER_RESTART, 'r') as f:
            mode = f.read()
        if mode in ('True', 'reload'):
            from src.server.oobhandler import OOB_HANDLER
            OOB_HANDLER.restore()

        from src.scripts.tickerhandler import TICKER_HANDLER
        TICKER_HANDLER.restore()

        if SERVER_STARTSTOP_MODULE:
            # call correct server hook based on start file value
            if mode in ('True', 'reload'):
                # True was the old reload flag, kept for compatibilty
                SERVER_STARTSTOP_MODULE.at_server_reload_start()
            elif mode in ('reset', 'shutdown'):
                SERVER_STARTSTOP_MODULE.at_server_cold_start()
                # clear eventual lingering session storages
                ObjectDB.objects.clear_all_sessids()
            # always call this regardless of start type
            SERVER_STARTSTOP_MODULE.at_server_start()
Example #6
0
    def run_init_hooks(self):
        """
        Called every server start
        """
        from src.objects.models import ObjectDB
        #from src.players.models import PlayerDB

        #update eventual changed defaults
        self.update_defaults()

        #print "run_init_hooks:", ObjectDB.get_all_cached_instances()
        [(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()]
        [(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()]

        with open(SERVER_RESTART, 'r') as f:
            mode = f.read()
        if mode in ('True', 'reload'):
            from src.server.oobhandler import OOB_HANDLER
            OOB_HANDLER.restore()

        from src.scripts.tickerhandler import TICKER_HANDLER
        TICKER_HANDLER.restore()

        # call correct server hook based on start file value
        if mode in ('True', 'reload'):
            # True was the old reload flag, kept for compatibilty
            self.at_server_reload_start()
        elif mode in ('reset', 'shutdown'):
            self.at_server_cold_start()
            # clear eventual lingering session storages
            ObjectDB.objects.clear_all_sessids()
        # always call this regardless of start type
        self.at_server_start()
Example #7
0
def reset_loop():
    "Reload and restart all entities that can be reloaded."    
    # run the reset loop on all objects
    cemit_info(" Resetting all cached database entities ...")
    t1 = time.time()
    [h.locks.reset() for h in HelpEntry.objects.all()]
    [m.locks.reset() for m in Msg.objects.all()]
    [c.locks.reset() for c in Channel.objects.all()]    
    [s.locks.reset() for s in ScriptDB.objects.all()]
    [(o.typeclass(o), o.cmdset.reset(), o.locks.reset(), o.at_cache()) for o in ObjectDB.get_all_cached_instances()]    
    [(p.typeclass(p), p.cmdset.reset(), p.locks.reset()) for p in PlayerDB.get_all_cached_instances()]

    t2 = time.time()
    cemit_info(" ... Reset finished in %g seconds." % (t2-t1))
Example #8
0
def _batch_create_object(*objparams):
    """
    This is a cut-down version of the create_object() function,
    optimized for speed. It does NOT check and convert various input
    so make sure the spawned Typeclass works before using this!

    Input:
    objsparams - each argument should be a tuple of arguments for the respective
                 creation/add handlers in the following order:
                    (create, permissions, locks, aliases, nattributes, attributes)
    Returns:
    A list of created objects
    """

    # bulk create all objects in one go
    dbobjs = [ObjectDB(**objparam[0]) for objparam in objparams]
    # unfortunately this doesn't work since bulk_create don't creates pks;
    # the result are double objects at the next stage
    #dbobjs = _ObjectDB.objects.bulk_create(dbobjs)

    objs = []
    for iobj, dbobj in enumerate(dbobjs):
        # call all setup hooks on each object
        objparam = objparams[iobj]
        obj = dbobj.typeclass  # this saves dbobj if not done already
        obj.basetype_setup()
        obj.at_object_creation()

        if objparam[1]:
            # permissions
            obj.permissions.add(objparam[1])
        if objparam[2]:
            # locks
            obj.locks.add(objparam[2])
        if objparam[3]:
            # aliases
            obj.aliases.add(objparam[3])
        if objparam[4]:
            # nattributes
            for key, value in objparam[4].items():
                obj.nattributes.add(key, value)
        if objparam[5]:
            # attributes
            keys, values = objparam[5].keys(), objparam[5].values()
            obj.attributes.batch_add(keys, values)

        obj.basetype_posthook_setup()
        objs.append(obj)
    return objs
Example #9
0
def create_object(typeclass=None,
                  key=None,
                  location=None,
                  home=None,
                  permissions=None,
                  locks=None,
                  aliases=None,
                  destination=None,
                  report_to=None,
                  nohome=False):
    """
    Create a new in-game object. Any game object is a combination
    of a database object that stores data persistently to
    the database, and a typeclass, which on-the-fly 'decorates'
    the database object into whataver different type of object
    it is supposed to be in the game.

    See src.objects.managers for methods to manipulate existing objects
    in the database. src.objects.objects holds the base typeclasses
    and src.objects.models hold the database model.

    report_to is an optional object for reporting errors to in string form.
              If report_to is not set, errors will be raised as en Exception
              containing the error message. If set, this method will return
              None upon errors.
    nohome - this allows the creation of objects without a default home location;
             this only used when creating the default location itself or during unittests
    """
    global _Object, _ObjectDB
    if not _Object:
        from src.objects.objects import Object as _Object
    if not _ObjectDB:
        from src.objects.models import ObjectDB as _ObjectDB

    # input validation

    if not typeclass:
        typeclass = settings.BASE_OBJECT_TYPECLASS
    elif isinstance(typeclass, _ObjectDB):
        # this is already an objectdb instance, extract its typeclass
        typeclass = typeclass.typeclass.path
    elif isinstance(typeclass, _Object) or utils.inherits_from(
            typeclass, _Object):
        # this is already an object typeclass, extract its path
        typeclass = typeclass.path
    typeclass = utils.to_unicode(typeclass)

    # Setup input for the create command

    location = handle_dbref(location, _ObjectDB)
    destination = handle_dbref(destination, _ObjectDB)
    home = handle_dbref(home, _ObjectDB)
    if not home:
        try:
            home = handle_dbref(settings.DEFAULT_HOME,
                                _ObjectDB) if not nohome else None
        except _ObjectDB.DoesNotExist:
            raise _ObjectDB.DoesNotExist(
                "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed."
                % settings.DEFAULT_HOME)

    # create new database object all in one go
    new_db_object = _ObjectDB(db_key=key,
                              db_location=location,
                              db_destination=destination,
                              db_home=home,
                              db_typeclass_path=typeclass)

    if not key:
        # the object should always have a key, so if not set we give a default
        new_db_object.key = "#%i" % new_db_object.dbid

    # this will either load the typeclass or the default one (will also save object)
    new_object = new_db_object.typeclass

    if not _GA(new_object, "is_typeclass")(typeclass, exact=True):
        # this will fail if we gave a typeclass as input and it still
        # gave us a default
        try:
            SharedMemoryModel.delete(new_db_object)
        except AssertionError:
            # this happens if object was never created
            pass
        if report_to:
            report_to = handle_dbref(report_to, _ObjectDB)
            _GA(report_to,
                "msg")("Error creating %s (%s).\n%s" %
                       (new_db_object.key, typeclass,
                        _GA(new_db_object, "typeclass_last_errmsg")))
            return None
        else:
            raise Exception(_GA(new_db_object, "typeclass_last_errmsg"))

    # from now on we can use the typeclass object
    # as if it was the database object.

    # call the hook methods. This is where all at_creation
    # customization happens as the typeclass stores custom
    # things on its database object.

    # note - this may override input keys, locations etc!
    new_object.basetype_setup()  # setup the basics of Exits, Characters etc.
    new_object.at_object_creation()

    # we want the input to override that set in the hooks, so
    # we re-apply those if needed
    if new_object.key != key:
        new_object.key = key
    if new_object.location != location:
        new_object.location = location
    if new_object.home != home:
        new_object.home = home
    if new_object.destination != destination:
        new_object.destination = destination

    # custom-given perms/locks do overwrite hooks
    if permissions:
        new_object.permissions.add(permissions)
    if locks:
        new_object.locks.add(locks)
    if aliases:
        new_object.aliases.add(aliases)

    # trigger relevant move_to hooks in order to display messages.
    if location:
        new_object.at_object_receive(new_object, None)
        new_object.at_after_move(new_object)

    # post-hook setup (mainly used by Exits)
    new_object.basetype_posthook_setup()

    return new_object
Example #10
0
    def shutdown(self, mode=None, _reactor_stopping=False):
        """
        Shuts down the server from inside it.

        mode - sets the server restart mode.
               'reload' - server restarts, no "persistent" scripts are stopped, at_reload hooks called.
               'reset' - server restarts, non-persistent scripts stopped, at_shutdown hooks called.
               'shutdown' - like reset, but server will not auto-restart.
               None - keep currently set flag from flag file.
        _reactor_stopping - this is set if server is stopped by a kill command OR this method was already called
                  once - in both cases the reactor is dead/stopping already.
        """
        if _reactor_stopping and hasattr(self, "shutdown_complete"):
            # this means we have already passed through this method once; we don't need
            # to run the shutdown procedure again.
            defer.returnValue(None)

        mode = self.set_restart_mode(mode)
        # call shutdown hooks on all cached objects

        from src.objects.models import ObjectDB
        #from src.players.models import PlayerDB
        from src.server.models import ServerConfig

        if mode == 'reload':
            # call restart hooks
            yield [(o.typeclass, o.at_server_reload()) for o in ObjectDB.get_all_cached_instances()]
            yield [(p.typeclass, p.at_server_reload()) for p in PlayerDB.get_all_cached_instances()]
            yield [(s.typeclass, s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()]
            yield self.sessions.all_sessions_portal_sync()
            ServerConfig.objects.conf("server_restart_mode", "reload")

            if SERVER_STARTSTOP_MODULE:
                SERVER_STARTSTOP_MODULE.at_server_reload_stop()

        else:
            if mode == 'reset':
                # don't call disconnect hooks on reset
                yield [(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()]
            else: # shutdown
                yield [_SA(p, "is_connected", False) for p in PlayerDB.get_all_cached_instances()]
                yield [(o.typeclass, o.at_disconnect(), o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()]

            yield [(p.typeclass, p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()]
            yield [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()]

            ServerConfig.objects.conf("server_restart_mode", "reset")

            if SERVER_STARTSTOP_MODULE:
                SERVER_STARTSTOP_MODULE.at_server_cold_stop()

        if SERVER_STARTSTOP_MODULE:
            SERVER_STARTSTOP_MODULE.at_server_stop()
        # if _reactor_stopping is true, reactor does not need to be stopped again.
        if os.name == 'nt' and os.path.exists(SERVER_PIDFILE):
            # for Windows we need to remove pid files manually
            os.remove(SERVER_PIDFILE)
        if not _reactor_stopping:
            # this will also send a reactor.stop signal, so we set a flag to avoid loops.
            self.shutdown_complete = True
            reactor.callLater(0, reactor.stop)
Example #11
0
    def shutdown(self, mode=None, _reactor_stopping=False):
        """
        Shuts down the server from inside it.

        mode - sets the server restart mode.
               'reload' - server restarts, no "persistent" scripts
                          are stopped, at_reload hooks called.
               'reset' - server restarts, non-persistent scripts stopped,
                         at_shutdown hooks called.
               'shutdown' - like reset, but server will not auto-restart.
               None - keep currently set flag from flag file.
        _reactor_stopping - this is set if server is stopped by a kill
                            command OR this method was already called
                             once - in both cases the reactor is
                             dead/stopping already.
        """
        if _reactor_stopping and hasattr(self, "shutdown_complete"):
            # this means we have already passed through this method
            # once; we don't need to run the shutdown procedure again.
            defer.returnValue(None)

        mode = self.set_restart_mode(mode)
        # call shutdown hooks on all cached objects

        from src.objects.models import ObjectDB
        #from src.players.models import PlayerDB
        from src.server.models import ServerConfig

        if mode == 'reload':
            # call restart hooks
            yield [(o.typeclass, o.at_server_reload())
                                   for o in ObjectDB.get_all_cached_instances()]
            yield [(p.typeclass, p.at_server_reload())
                                   for p in PlayerDB.get_all_cached_instances()]
            yield [(s.typeclass, s.pause(), s.at_server_reload())
                                   for s in ScriptDB.get_all_cached_instances()]
            yield self.sessions.all_sessions_portal_sync()
            ServerConfig.objects.conf("server_restart_mode", "reload")

            from src.server.oobhandler import OOB_HANDLER
            OOB_HANDLER.save()
            from src.scripts.tickerhandler import TICKER_HANDLER
            TICKER_HANDLER.save()

            if SERVER_STARTSTOP_MODULE:
                SERVER_STARTSTOP_MODULE.at_server_reload_stop()

        else:
            if mode == 'reset':
                # don't unset the is_connected flag on reset, otherwise
                # same as shutdown
                yield [(o.typeclass, o.at_server_shutdown())
                                   for o in ObjectDB.get_all_cached_instances()]
                yield [(p.typeclass, p.at_server_shutdown())
                                       for p in PlayerDB.get_all_cached_instances()]
            else:  # shutdown
                yield [_SA(p, "is_connected", False)
                                   for p in PlayerDB.get_all_cached_instances()]
                yield [(o.typeclass, o.at_server_shutdown())
                                   for o in ObjectDB.get_all_cached_instances()]
                yield [(p.typeclass, p.unpuppet_all(), p.at_server_shutdown())
                                       for p in PlayerDB.get_all_cached_instances()]
            yield [(s.typeclass, s.at_server_shutdown())
                                   for s in ScriptDB.get_all_cached_instances()]
            yield ObjectDB.objects.clear_all_sessids()
            ServerConfig.objects.conf("server_restart_mode", "reset")

            if SERVER_STARTSTOP_MODULE:
                SERVER_STARTSTOP_MODULE.at_server_cold_stop()

        # stopping time
        from src.utils import gametime
        gametime.save()

        if SERVER_STARTSTOP_MODULE:
            SERVER_STARTSTOP_MODULE.at_server_stop()
        # if _reactor_stopping is true, reactor does not need to
        # be stopped again.
        if os.name == 'nt' and os.path.exists(SERVER_PIDFILE):
            # for Windows we need to remove pid files manually
            os.remove(SERVER_PIDFILE)
        if not _reactor_stopping:
            # this will also send a reactor.stop signal, so we set a
            # flag to avoid loops.
            self.shutdown_complete = True
            reactor.callLater(0, reactor.stop)
Example #12
0
def dummy(item):
    """This function exists for types we don't want to do anything with yet."""
    thing = ObjectDB(name=item["name"])
    thing.save()
Example #13
0
def create_object(typeclass=None,
                  key=None,
                  location=None,
                  home=None,
                  permissions=None,
                  locks=None,
                  aliases=None,
                  destination=None,
                  report_to=None,
                  nohome=False):
    """
    Create a new in-game object. Any game object is a combination
    of a database object that stores data persistently to
    the database, and a typeclass, which on-the-fly 'decorates'
    the database object into whataver different type of object
    it is supposed to be in the game.

    See src.objects.managers for methods to manipulate existing objects
    in the database. src.objects.objects holds the base typeclasses
    and src.objects.models hold the database model.

    report_to is an optional object for reporting errors to in string form.
              If report_to is not set, errors will be raised as en Exception
              containing the error message. If set, this method will return
              None upon errors.
    nohome - this allows the creation of objects without a default home location;
             this only used when creating default location itself or during unittests
    """
    global _Object, _ObjectDB
    if not _Object:
        from src.objects.objects import Object as _Object
    if not _ObjectDB:
        from src.objects.models import ObjectDB as _ObjectDB

    # input validation

    if not typeclass:
        typeclass = settings.BASE_OBJECT_TYPECLASS
    elif isinstance(typeclass, _ObjectDB):
        # this is already an objectdb instance, extract its typeclass
        typeclass = typeclass.typeclass.path
    elif isinstance(typeclass, _Object) or utils.inherits_from(
            typeclass, _Object):
        # this is already an object typeclass, extract its path
        typeclass = typeclass.path

    # handle eventual #dbref input
    location = handle_dbref(location, _ObjectDB)
    home = handle_dbref(home, _ObjectDB)
    destination = handle_dbref(destination, _ObjectDB)
    report_to = handle_dbref(report_to, _ObjectDB)

    # create new database object
    new_db_object = _ObjectDB()

    # assign the typeclass
    typeclass = utils.to_unicode(typeclass)
    new_db_object.typeclass_path = typeclass

    # the name/key is often set later in the typeclass. This
    # is set here as a failsafe.
    if key:
        new_db_object.key = key
    else:
        new_db_object.key = "#%i" % new_db_object.dbid

    # this will either load the typeclass or the default one
    new_object = new_db_object.typeclass

    if not _GA(new_object, "is_typeclass")(typeclass, exact=True):
        # this will fail if we gave a typeclass as input and it still
        # gave us a default
        SharedMemoryModel.delete(new_db_object)
        if report_to:
            _GA(report_to,
                "msg")("Error creating %s (%s):\n%s" %
                       (new_db_object.key, typeclass,
                        _GA(new_db_object, "typeclass_last_errmsg")))
            return None
        else:
            raise Exception(_GA(new_db_object, "typeclass_last_errmsg"))

    # from now on we can use the typeclass object
    # as if it was the database object.

    new_object.destination = destination

    # 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 perms/locks overwrite hooks
    if permissions:
        new_object.permissions.add(permissions)
    if locks:
        new_object.locks.add(locks)
    if aliases:
        new_object.aliases.add(aliases)

    if home:
        new_object.home = home
    else:
        # we shouldn't need to handle dbref here (home handler should fix it), but some have
        # reported issues here (issue 446).
        try:
            new_object.home = handle_dbref(settings.DEFAULT_HOME,
                                           _ObjectDB) if not nohome else None
        except _ObjectDB.DoesNotExist:
            raise _ObjectDB.DoesNotExist(
                "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed."
                % settings.DEFAULT_HOME)

    # perform a move_to in order to display eventual messages.
    if location:
        new_object.move_to(location, quiet=True)
    else:
        # rooms would have location=None.
        new_object.location = None

    # post-hook setup (mainly used by Exits)
    new_object.basetype_posthook_setup()

    new_object.save()
    return new_object