diff --git a/contrib/menusystem.py b/contrib/menusystem.py index 8a32db155c..adc97dfb28 100644 --- a/contrib/menusystem.py +++ b/contrib/menusystem.py @@ -149,15 +149,19 @@ class MenuTree(object): 'START' and 'END' respectively. """ - def __init__(self, caller, nodes=None, startnode="START", endnode="END"): + def __init__(self, caller, nodes=None, startnode="START", endnode="END", exec_end="look"): """ We specify startnode/endnode so that the system knows where to enter and where to exit the menu tree. If nodes is given, it shuld be a list of valid node objects to add to the tree. + + exec_end - if not None, will execute the given command string + directly after the menu system has been exited. """ self.tree = {} self.startnode = startnode self.endnode = endnode + self.exec_end = exec_end self.caller = caller if nodes and utils.is_iter(nodes): for node in nodes: @@ -186,7 +190,8 @@ class MenuTree(object): # if we was given the END node key, we clean up immediately. self.caller.cmdset.delete("menucmdset") del self.caller.db._menu_data - self.caller.execute_cmd("look") + if self.exec_end != None: + self.caller.execute_cmd(self.exec_end) return # not exiting, look for a valid code. node = self.tree.get(key, None) diff --git a/game/gamesrc/objects/baseobjects.py b/game/gamesrc/objects/baseobjects.py index f4b9a9470f..e8603438b7 100644 --- a/game/gamesrc/objects/baseobjects.py +++ b/game/gamesrc/objects/baseobjects.py @@ -128,7 +128,7 @@ class Character(BaseCharacter): # save location again to be sure self.db.prelogout_location = self.location - self.location.msg_contents("%s has entered the game." % self.name) + self.location.msg_contents("%s has entered the game." % self.name, exclude=[self]) self.location.at_object_receive(self, self.location) class Room(BaseRoom): diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index 8ae98f9560..ba802c1e3b 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -50,11 +50,17 @@ COMMAND_PARSER = utils.mod_import(*settings.COMMAND_PARSER.rsplit('.', 1)) # allow for custom behaviour when the command handler hits # special situations -- it then calls a normal Command # that you can customize! +# Import these variables and use them rather than trying +# to remember the actual string constants. CMD_NOINPUT = "__noinput_command" CMD_NOMATCH = "__nomatch_command" CMD_MULTIMATCH = "__multimatch_command" -CMD_CHANNEL = "__send_to_channel" +CMD_CHANNEL = "__send_to_channel_command" +# this is the name of the command the engine calls when the player +# connects. It is expected to show the login screen. +CMD_LOGINSTART = "__unloggedin_look_command" + class NoCmdSets(Exception): "No cmdsets found. Critical error." diff --git a/src/commands/default/unloggedin.py b/src/commands/default/unloggedin.py index 57f999972b..6f2d8486ff 100644 --- a/src/commands/default/unloggedin.py +++ b/src/commands/default/unloggedin.py @@ -13,6 +13,7 @@ from src.comms.models import Channel from src.utils import create, logger, utils, ansi from src.commands.default.muxcommand import MuxCommand +from src.commands.cmdhandler import CMD_LOGINSTART CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE @@ -221,10 +222,12 @@ class CmdQuit(MuxCommand): class CmdUnconnectedLook(MuxCommand): """ This is an unconnected version of the look command for simplicity. - All it does is re-show the connect screen. + + This is called by the server and kicks everything in gear. + All it does is display the connect screen. """ - key = "look" - aliases = "l" + key = CMD_LOGINSTART + aliases = ["look", "l"] locks = "cmd:all()" def func(self): diff --git a/src/server/serversession.py b/src/server/serversession.py index 4bcba0201f..450508e755 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -59,10 +59,6 @@ class ServerSession(Session): # start (persistent) scripts on this object ScriptDB.objects.validate(obj=character) - def at_cmdset_get(self): - "dummy hook all objects with cmdsets need to have" - pass - def session_login(self, player): """ Startup mechanisms that need to run at login. This is called @@ -96,11 +92,10 @@ class ServerSession(Session): player.at_pre_login() character = player.character - #print "at_init() - character" - character.at_init() if character: # this player has a character. Check if it's the # first time *this character* logs in + character.at_init() if character.db.FIRST_LOGIN: character.at_first_login() del character.db.FIRST_LOGIN @@ -190,7 +185,7 @@ class ServerSession(Session): if str(command_string).strip() == IDLE_COMMAND: self.update_session_counters(idle=True) return - + # all other inputs, including empty inputs character = self.get_character() @@ -216,6 +211,7 @@ class ServerSession(Session): def __eq__(self, other): return self.address == other.address + def __str__(self): """ String representation of the user session class. We use @@ -249,3 +245,57 @@ class ServerSession(Session): def msg(self, string='', data=None): "alias for at_data_out" self.data_out(string, data=data) + + + # Dummy API hooks for use a non-loggedin operation + + def at_cmdset_get(self): + "dummy hook all objects with cmdsets need to have" + pass + + # Mock db/ndb properties for allowing easy storage on the session + # (note that no databse is involved at all here. session.db.attr = + # value just saves a normal property in memory, just like ndb). + + #@property + def ndb_get(self): + """ + A non-persistent store (ndb: NonDataBase). Everything stored + to this is guaranteed to be cleared when a server is shutdown. + Syntax is same as for the _get_db_holder() method and + property, e.g. obj.ndb.attr = value etc. + """ + try: + return self._ndb_holder + except AttributeError: + class NdbHolder(object): + "Holder for storing non-persistent attributes." + def all(self): + return [val for val in self.__dict__.keys() + if not val.startswith['_']] + def __getattribute__(self, key): + # return None if no matching attribute was found. + try: + return object.__getattribute__(self, key) + except AttributeError: + return None + self._ndb_holder = NdbHolder() + return self._ndb_holder + #@ndb.setter + def ndb_set(self, value): + "Stop accidentally replacing the db object" + string = "Cannot assign directly to ndb object! " + string = "Use ndb.attr=value instead." + raise Exception(string) + #@ndb.deleter + def ndb_del(self): + "Stop accidental deletion." + raise Exception("Cannot delete the ndb object!") + ndb = property(ndb_get, ndb_set, ndb_del) + db = property(ndb_get, ndb_set, ndb_del) + + # Mock access method for the session (there is no lock info + # at this stage, so we just present a uniform API) + def access(self, *args, **kwargs): + "Dummy method." + return True diff --git a/src/server/sessionhandler.py b/src/server/sessionhandler.py index 952458a8fa..37937ffb71 100644 --- a/src/server/sessionhandler.py +++ b/src/server/sessionhandler.py @@ -19,6 +19,8 @@ from django.contrib.auth.models import User from src.server.models import ServerConfig from src.utils import utils +from src.commands.cmdhandler import CMD_LOGINSTART + # i18n from django.utils.translation import ugettext as _ @@ -94,7 +96,7 @@ class ServerSessionHandler(SessionHandler): Creates a new, unlogged-in game session. """ self.sessions[sessid] = session - session.execute_cmd('look') + session.execute_cmd(CMD_LOGINSTART) def portal_disconnect(self, sessid): """