diff --git a/game/evennia.py b/game/evennia.py index c5c4a130d1..aca814046d 100755 --- a/game/evennia.py +++ b/game/evennia.py @@ -2,7 +2,7 @@ """ EVENNIA SERVER STARTUP SCRIPT -This is the start point for running Evennia. +This is the start point for running Evennia. Sets the appropriate environmental variables and launches the server and portal through the runner. Run without arguments to get a @@ -47,12 +47,12 @@ if not os.path.exists('settings.py'): When you are set up, run evennia.py again to start the server.""" sys.exit() -# signal processing +# signal processing SIG = signal.SIGINT HELPENTRY = \ """ - (version %s) + (version %s) This program launches Evennia with various options. You can access all this functionality directly from the command line; for example option @@ -83,7 +83,7 @@ directly see tracebacks on standard output, so starting with options server (option 5) to make it available to users. Reload and stop is not well supported in Windows. If you have issues, log -into the game to stop or restart the server instead. +into the game to stop or restart the server instead. """ MENU = \ @@ -160,7 +160,7 @@ except DatabaseError: Your database does not seem to be set up correctly. Please run: - + python manage.py syncdb (make sure to create an admin user when prompted). If you use @@ -231,7 +231,7 @@ if os.name == 'nt': # Functions - + def get_pid(pidfile): """ Get the PID (Process ID) by trying to access @@ -319,7 +319,7 @@ def run_menu(): if inp == 5: if os.name == 'nt': print "This operation is not supported under Windows. Log into the game to restart/reload the server." - return + return kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % "Server") elif inp == 6: if os.name == 'nt': @@ -353,8 +353,8 @@ def handle_args(options, mode, service): errmsg = "The %s does not seem to be running." if mode == 'start': - - # launch the error checker. Best to catch the errors already here. + + # launch the error checker. Best to catch the errors already here. error_check_python_modules() # starting one or many services @@ -376,13 +376,13 @@ def handle_args(options, mode, service): # restarting services if os.name == 'nt': print "Restarting from command line is not supported under Windows. Log into the game to restart." - return + return if service == 'server': kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server') elif service == 'portal': print """ Note: Portal usually don't need to be reloaded unless you are debugging in interactive mode. - If Portal was running in default Daemon mode, it cannot be restarted. In that case you have + If Portal was running in default Daemon mode, it cannot be restarted. In that case you have to restart it manually with 'evennia.py start portal' """ kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped, if it was in daemon mode).", errmsg % 'Portal', PORTAL_RESTART) @@ -408,7 +408,7 @@ def error_check_python_modules(): with exceptions in the engine (since they are formatting errors in the python source files themselves). Best they fail already here before we get any further. - """ + """ def imp(path, split=True): mod, fromlist = path, "None" if split: @@ -473,12 +473,12 @@ def main(): # handle command-line arguments cmdstr = handle_args(options, mode, service) if cmdstr: - # call the runner. + # call the runner. cmdstr.append('start') Popen(cmdstr) if __name__ == '__main__': - # start Evennia + # start Evennia from src.utils.utils import check_evennia_dependencies if check_evennia_dependencies(): main() diff --git a/game/gamesrc/commands/examples/cmdset.py b/game/gamesrc/commands/examples/cmdset.py index b429a8f71e..62b0665ce8 100644 --- a/game/gamesrc/commands/examples/cmdset.py +++ b/game/gamesrc/commands/examples/cmdset.py @@ -1,10 +1,10 @@ """ -Example command set template module. +Example command set template module. To create new commands to populate the cmdset, see examples/command.py. -To extend the default command set: +To extend the default command set: - copy this file up one level to gamesrc/commands and name it something fitting. - change settings.CMDSET_DEFAULT to point to the new module's @@ -36,12 +36,12 @@ class ExampleCmdSet(CmdSet): """ Implements an empty, example cmdset. """ - + key = "ExampleSet" def at_cmdset_creation(self): """ - This is the only method defined in a cmdset, called during + This is the only method defined in a cmdset, called during its creation. It should populate the set with command instances. Here we just add the empty base Command object. It prints some info. @@ -51,7 +51,7 @@ class ExampleCmdSet(CmdSet): class DefaultCmdSet(default_cmds.DefaultCmdSet): """ - This is an example of how to overload the default command + This is an example of how to overload the default command set defined in src/commands/default/cmdset_default.py. Here we copy everything by calling the parent, but you can @@ -60,7 +60,7 @@ class DefaultCmdSet(default_cmds.DefaultCmdSet): to this class. """ key = "DefaultMUX" - + def at_cmdset_creation(self): """ Populates the cmdset @@ -72,8 +72,8 @@ class DefaultCmdSet(default_cmds.DefaultCmdSet): # any commands you add below will overload the default ones. # #self.add(menusystem.CmdMenuTest()) - #self.add(lineeditor.CmdEditor()) - #self.add(misc_commands.CmdQuell()) + #self.add(lineeditor.CmdEditor()) + #self.add(misc_commands.CmdQuell()) class UnloggedinCmdSet(default_cmds.UnloggedinCmdSet): """ @@ -87,25 +87,25 @@ class UnloggedinCmdSet(default_cmds.UnloggedinCmdSet): point to this class. """ key = "Unloggedin" - + def at_cmdset_creation(self): """ Populates the cmdset """ # calling setup in src.commands.default.cmdset_unloggedin super(UnloggedinCmdSet, self).at_cmdset_creation() - + # # any commands you add below will overload the default ones. # class OOCCmdSet(default_cmds.OOCCmdSet): """ - This is set is available to the player when they have no + This is set is available to the player when they have no character connected to them (i.e. they are out-of-character, ooc). """ key = "OOC" - + def at_cmdset_creation(self): """ Populates the cmdset @@ -114,9 +114,4 @@ class OOCCmdSet(default_cmds.OOCCmdSet): super(OOCCmdSet, self).at_cmdset_creation() # # any commands you add below will overload the default ones. - # - - - - - + # diff --git a/game/gamesrc/commands/examples/cmdset_red_button.py b/game/gamesrc/commands/examples/cmdset_red_button.py index b22c003f51..ba7c61b17c 100644 --- a/game/gamesrc/commands/examples/cmdset_red_button.py +++ b/game/gamesrc/commands/examples/cmdset_red_button.py @@ -1,13 +1,13 @@ """ This defines the cmdset for the red_button. Here we have defined the commands and the cmdset in the same module, but if you -have many different commands to merge it is often better +have many different commands to merge it is often better to define the cmdset separately, picking and choosing from -among the available commands as to what should be included in the +among the available commands as to what should be included in the cmdset - this way you can often re-use the commands too. """ -import random +import random from ev import Command, CmdSet # Some simple commands for the red button @@ -19,14 +19,14 @@ from ev import Command, CmdSet class CmdNudge(Command): """ Try to nudge the button's lid - - Usage: + + Usage: nudge lid - This command will have you try to - push the lid of the button away. + This command will have you try to + push the lid of the button away. """ - + key = "nudge lid" # two-word command name! aliases = ["nudge"] locks = "cmd:all()" @@ -43,10 +43,10 @@ class CmdNudge(Command): else: self.caller.msg("You manage to get a nail under the lid.") self.caller.execute_cmd("open lid") - + class CmdPush(Command): """ - Push the red button + Push the red button Usage: push button @@ -55,7 +55,7 @@ class CmdPush(Command): key = "push button" aliases = ["push", "press button", "press"] locks = "cmd:all()" - + def func(self): """ Note that we choose to implement this with checking for @@ -64,7 +64,7 @@ class CmdPush(Command): An alternative would be to make two versions of this command and tuck them into the cmdset linked to the Open and Closed - lid-state respectively. + lid-state respectively. """ @@ -72,15 +72,15 @@ class CmdPush(Command): string = "You reach out to press the big red button ..." string += "\n\nA BOOM! A bright light blinds you!" string += "\nThe world goes dark ..." - self.caller.msg(string) - self.caller.location.msg_contents("%s presses the button. BOOM! %s is blinded by a flash!" % + self.caller.msg(string) + self.caller.location.msg_contents("%s presses the button. BOOM! %s is blinded by a flash!" % (self.caller.name, self.caller.name), exclude=self.caller) # the button's method will handle all setup of scripts etc. - self.obj.press_button(self.caller) + self.obj.press_button(self.caller) else: string = "You cannot push the button - there is a glass lid covering it." self.caller.msg(string) - + class CmdSmashGlass(Command): @@ -92,15 +92,15 @@ class CmdSmashGlass(Command): Try to smash the glass of the button. """ - + key = "smash glass" aliases = ["smash lid", "break lid", "smash"] locks = "cmd:all()" - + def func(self): """ The lid won't open, but there is a small chance - of causing the lamp to break. + of causing the lamp to break. """ rand = random.random() @@ -109,11 +109,11 @@ class CmdSmashGlass(Command): string += " with all your might. The lid won't budge" string += " but you cause quite the tremor through the button's mount." string += "\nIt looks like the button's lamp stopped working for the time being." - self.obj.lamp_works = False + self.obj.lamp_works = False elif rand < 0.6: string = "You hit the lid hard. It doesn't move an inch." else: - string = "You place a well-aimed fist against the glass of the lid." + string = "You place a well-aimed fist against the glass of the lid." string += " Unfortunately all you get is a pain in your hand. Maybe" string += " you should just try to open the lid instead?" self.caller.msg(string) @@ -125,7 +125,7 @@ class CmdOpenLid(Command): open lid Usage: - open lid + open lid """ @@ -135,21 +135,21 @@ class CmdOpenLid(Command): def func(self): "simply call the right function." - + if self.obj.db.lid_locked: self.caller.msg("This lid seems locked in place for the moment.") - return + return string = "\nA ticking sound is heard, like a winding mechanism. Seems " string += "the lid will soon close again." self.caller.msg(string) - self.caller.location.msg_contents("%s opens the lid of the button." % + self.caller.location.msg_contents("%s opens the lid of the button." % (self.caller.name), exclude=self.caller) - # add the relevant cmdsets to button + # add the relevant cmdsets to button self.obj.cmdset.add(LidClosedCmdSet) # call object method self.obj.open_lid() - + class CmdCloseLid(Command): """ close the lid @@ -163,7 +163,7 @@ class CmdCloseLid(Command): key = "close lid" aliases = ["close"] locks = "cmd:all()" - + def func(self): "Close the lid" @@ -171,9 +171,9 @@ class CmdCloseLid(Command): # this will clean out scripts dependent on lid being open. self.caller.msg("You close the button's lid. It clicks back into place.") - self.caller.location.msg_contents("%s closes the button's lid." % + self.caller.location.msg_contents("%s closes the button's lid." % (self.caller.name), exclude=self.caller) - + class CmdBlindLook(Command): """ Looking around in darkness @@ -185,14 +185,14 @@ class CmdBlindLook(Command): """ - key = "look" + key = "look" aliases = ["l", "get", "examine", "ex", "feel", "listen"] locks = "cmd:all()" - + def func(self): "This replaces all the senses when blinded." - # we decide what to reply based on which command was + # we decide what to reply based on which command was # actually tried if self.cmdstring == "get": @@ -208,7 +208,7 @@ class CmdBlindLook(Command): string = "You are temporarily blinded by the flash. " string += "Until it wears off, all you can do is feel around blindly." self.caller.msg(string) - self.caller.location.msg_contents("%s stumbles around, blinded." % + self.caller.location.msg_contents("%s stumbles around, blinded." % (self.caller.name), exclude=self.caller) class CmdBlindHelp(Command): @@ -220,7 +220,7 @@ class CmdBlindHelp(Command): """ key = "help" - aliases = "h" + aliases = "h" locks = "cmd:all()" def func(self): @@ -242,13 +242,13 @@ class DefaultCmdSet(CmdSet): The default cmdset always sits on the button object and whereas other command sets may be added/merge onto it - and hide it, removing them will always + and hide it, removing them will always bring it back. It's added to the object using obj.cmdset.add_default(). """ key = "RedButtonDefault" - mergetype = "Union" # this is default, we don't really need to put it here. - + mergetype = "Union" # this is default, we don't really need to put it here. + def at_cmdset_creation(self): "Init the cmdset" self.add(CmdPush()) @@ -260,13 +260,13 @@ class LidClosedCmdSet(CmdSet): It contains the commands that launches the other command sets, making the red button a self-contained item (i.e. you don't have to manually add any - scripts etc to it when creating it). + scripts etc to it when creating it). """ key = "LidClosedCmdSet" - # default Union is used *except* if we are adding to a - # cmdset named LidOpenCmdSet - this one we replace + # default Union is used *except* if we are adding to a + # cmdset named LidOpenCmdSet - this one we replace # completely. - key_mergetype = {"LidOpenCmdSet": "Replace"} + key_mergetype = {"LidOpenCmdSet": "Replace"} def at_cmdset_creation(self): "Populates the cmdset when it is instantiated." @@ -276,14 +276,14 @@ class LidClosedCmdSet(CmdSet): class LidOpenCmdSet(CmdSet): """ - This is the opposite of the Closed cmdset. + This is the opposite of the Closed cmdset. """ key = "LidOpenCmdSet" - # default Union is used *except* if we are adding to a - # cmdset named LidClosedCmdSet - this one we replace + # default Union is used *except* if we are adding to a + # cmdset named LidClosedCmdSet - this one we replace # completely. key_mergetype = {"LidClosedCmdSet": "Replace"} - + def at_cmdset_creation(self): "setup the cmdset (just one command)" self.add(CmdCloseLid()) @@ -295,13 +295,13 @@ class BlindCmdSet(CmdSet): """ key = "BlindCmdSet" # we want it to completely replace all normal commands - # until the timed script removes it again. - mergetype = "Replace" + # until the timed script removes it again. + mergetype = "Replace" # we want to stop the player from walking around # in this blinded state, so we hide all exits too. # (channel commands will still work). no_exits = True # keep player in the same room - no_objs = True # don't allow object commands + no_objs = True # don't allow object commands def at_cmdset_creation(self): "Setup the blind cmdset" diff --git a/game/gamesrc/commands/examples/command.py b/game/gamesrc/commands/examples/command.py index 0130c70269..c5ba0e7393 100644 --- a/game/gamesrc/commands/examples/command.py +++ b/game/gamesrc/commands/examples/command.py @@ -1,5 +1,5 @@ """ -Example command module template +Example command module template Copy this module up one level to gamesrc/commands/ and name it as befits your use. You can then use it as a template to define your new @@ -15,30 +15,30 @@ from ev import utils class Command(BaseCommand): """ Inherit from this if you want to create your own - command styles. Note that Evennia's default commands + command styles. Note that Evennia's default commands use MuxCommand instead (next in this module) Note that the class's __doc__ string (this text) is used by Evennia to create the automatic help entry for - the command, so make sure to document consistently here. + the command, so make sure to document consistently here. """ - # these need to be specified - + # these need to be specified + key = "MyCommand" - aliases = ["mycmd", "myc"] + aliases = ["mycmd", "myc"] locks = "cmd:all()" help_category = "General" # auto_help = False # uncomment to deactive auto-help for this command. - # arg_regex = r"\s.*?|$" # optional regex detailing how the part after + # arg_regex = r"\s.*?|$" # optional regex detailing how the part after # the cmdname must look to match this command. # (we don't implement hook method access() here, you don't need to # modify that unless you want to change how the lock system works # (in that case see src.commands.command.Command)) - + def at_pre_cmd(self): """ This hook is called before self.parse() on all commands @@ -51,15 +51,15 @@ class Command(BaseCommand): has been identified. It creates a new set of member variables that can be later accessed from self.func() (see below) - The following variables are available to us: - # class variables: + The following variables are available to us: + # class variables: self.key - the name of this command ('mycommand') self.aliases - the aliases of this cmd ('mycmd','myc') self.locks - lock string for this command ("cmd:all()") self.help_category - overall category of command ("General") - - # added at run-time by cmdhandler: + + # added at run-time by cmdhandler: self.caller - the object calling this command self.cmdstring - the actual command name used to call this @@ -67,10 +67,10 @@ class Command(BaseCommand): for example) self.args - the raw input; everything following self.cmdstring. self.cmdset - the cmdset from which this command was picked. Not - often used (useful for commands like 'help' or to + often used (useful for commands like 'help' or to list all available commands etc) self.obj - the object on which this command was defined. It is often - the same as self.caller. + the same as self.caller. """ pass @@ -78,13 +78,13 @@ class Command(BaseCommand): """ This is the hook function that actually does all the work. It is called by the cmdhandler right after self.parser() finishes, and so has access - to all the variables defined therein. + to all the variables defined therein. """ self.caller.msg("Command called!") def at_post_cmd(self): """ - This hook is called after self.func(). + This hook is called after self.func(). """ pass @@ -101,32 +101,32 @@ class MuxCommand(default_cmd.MuxCommand): name[ with several words][/switch[/switch..]] arg1[,arg2,...] [[=|,] arg[,..]] The 'name[ with several words]' part is already dealt with by the - cmdhandler at this point, and stored in self.cmdname. The rest is stored - in self.args. + cmdhandler at this point, and stored in self.cmdname. The rest is stored + in self.args. - The MuxCommand parser breaks self.args into its constituents and stores them in the - following variables: + The MuxCommand parser breaks self.args into its constituents and stores them in the + following variables: self.switches = optional list of /switches (without the /) self.raw = This is the raw argument input, including switches self.args = This is re-defined to be everything *except* the switches - self.lhs = Everything to the left of = (lhs:'left-hand side'). If + self.lhs = Everything to the left of = (lhs:'left-hand side'). If no = is found, this is identical to self.args. - self.rhs: Everything to the right of = (rhs:'right-hand side'). + self.rhs: Everything to the right of = (rhs:'right-hand side'). If no '=' is found, this is None. self.lhslist - self.lhs split into a list by comma self.rhslist - list of self.rhs split into a list by comma self.arglist = list of space-separated args (including '=' if it exists) - All args and list members are stripped of excess whitespace around the - strings, but case is preserved. + All args and list members are stripped of excess whitespace around the + strings, but case is preserved. """ - + def func(self): """ This is the hook function that actually does all the work. It is called by the cmdhandler right after self.parser() finishes, and so has access - to all the variables defined therein. - """ - # this can be removed in your child class, it's just + to all the variables defined therein. + """ + # this can be removed in your child class, it's just # printing the ingoing variables as a demo. super(MuxCommand, self).func() diff --git a/game/gamesrc/conf/examples/at_initial_setup.py b/game/gamesrc/conf/examples/at_initial_setup.py index 12d68a50e4..0b0fb08b0d 100644 --- a/game/gamesrc/conf/examples/at_initial_setup.py +++ b/game/gamesrc/conf/examples/at_initial_setup.py @@ -2,7 +2,7 @@ At_initial_setup module template Copy this module up one level to /gamesrc/conf, name it what you like -and then use it as a template to modify. +and then use it as a template to modify. Then edit settings.AT_INITIAL_SETUP_HOOK_MODULE to point to your new module. @@ -21,4 +21,4 @@ does what you expect it to. """ def at_initial_setup(): - pass + pass diff --git a/game/gamesrc/conf/examples/at_server_startstop.py b/game/gamesrc/conf/examples/at_server_startstop.py index 46a89d7cda..9d9fbb5c61 100644 --- a/game/gamesrc/conf/examples/at_server_startstop.py +++ b/game/gamesrc/conf/examples/at_server_startstop.py @@ -3,7 +3,7 @@ At_server_startstop module template Copy this module one level up, to gamesrc/conf/, name it what you -will and use it as a template for your modifications. +will and use it as a template for your modifications. Then edit settings.AT_SERVER_STARTSTOP_MODULE to point to your new module. @@ -15,10 +15,10 @@ already been executed. The main purpose of this is module is to have a safe place to initialize eventual custom modules that your game needs to start up or load. -The module should define at least these global functions: +The module should define at least these global functions: -at_server_start() -at_server_stop() +at_server_start() +at_server_stop() """ diff --git a/game/gamesrc/conf/examples/connection_screens.py b/game/gamesrc/conf/examples/connection_screens.py index 5b25dc44e0..a2fe86cf08 100644 --- a/game/gamesrc/conf/examples/connection_screens.py +++ b/game/gamesrc/conf/examples/connection_screens.py @@ -1,8 +1,8 @@ """ -Connect screen module template +Connect screen module template Copy this module one level up, to gamesrc/conf/, name it what -you want and modify it to your liking. +you want and modify it to your liking. Then you set settings.CONNECTION_SCREEN_MODULE to point to your new module. @@ -10,7 +10,7 @@ new module. This module holds textual connection screen definitions. All global string variables (only) in this module are read by Evennia and - assumed to define a Connection screen. + assumed to define a Connection screen. The names of the string variables doesn't matter (except they shouldn't start with _), but each should hold a string defining a @@ -25,13 +25,13 @@ new module. """ -from src.utils import utils +from src.utils import utils from src.commands.connection_screen import DEFAULT_SCREEN # # CUSTOM_SCREEN = \ # """{b=============================================================={n -# Welcome to {gEvennia{n, version %s! +# Welcome to {gEvennia{n, version %s! # # If you have an existing account, connect to it by typing: # {wconnect {n @@ -45,5 +45,5 @@ from src.commands.connection_screen import DEFAULT_SCREEN # MENU_SCREEN = \ # """{b=============================================================={n -# Welcome to {gEvennnia{n, version %s! +# Welcome to {gEvennnia{n, version %s! # {b=============================================================={n""" % utils.get_evennia_version() diff --git a/game/gamesrc/conf/examples/lockfuncs.py b/game/gamesrc/conf/examples/lockfuncs.py index 717ac8559d..a3f3e931fc 100644 --- a/game/gamesrc/conf/examples/lockfuncs.py +++ b/game/gamesrc/conf/examples/lockfuncs.py @@ -3,9 +3,9 @@ Lockfuncs module template Copy this module one level up, to gamesrc/conf/, name it what -you will and edit it to your liking. +you will and edit it to your liking. -Then add the new module's path to the end of the tuple +Then add the new module's path to the end of the tuple defined in settings.LOCK_FUNC_MODULES. All functions defined globally in this module are assumed to be @@ -18,15 +18,15 @@ arguments should be handled (excess ones calling magic (*args, **kwargs) to avoid errors). The lock function should handle all eventual tracebacks by logging the error and returning False. -See many more examples of lock functions in src.locks.lockfuncs. +See many more examples of lock functions in src.locks.lockfuncs. """ def myfalse(accessing_obj, accessed_obj, *args, **kwargs): """ - called in lockstring with myfalse(). + called in lockstring with myfalse(). A simple logger that always returns false. Prints to stdout for simplicity, should use utils.logger for real operation. """ print "%s tried to access %s. Access denied." % (accessing_obj, accessed_obj) - return False + return False diff --git a/game/gamesrc/conf/examples/mssp.py b/game/gamesrc/conf/examples/mssp.py index 733cf4a525..df005aaa48 100644 --- a/game/gamesrc/conf/examples/mssp.py +++ b/game/gamesrc/conf/examples/mssp.py @@ -1,22 +1,22 @@ """ -MSSP module template +MSSP module template Copy this module one level up, to gamesrc/conf/, name it -what you want and edit it to your satisfaction. +what you want and edit it to your satisfaction. Then change settings.MSSP_META_MODULE to point to your new module. - MSSP (Mud Server Status Protocol) meta information + MSSP (Mud Server Status Protocol) meta information MUD website listings (that you have registered with) can use this information to keep up-to-date with your game stats as you change them. Also number of currently active players and uptime will automatically be reported. You don't have to fill in everything (and most are not used by all crawlers); leave the default - if so needed. You need to @reload the game before updated - information is made available to crawlers (reloading does not - affect uptime). + if so needed. You need to @reload the game before updated + information is made available to crawlers (reloading does not + affect uptime). """ MSSPTable = { @@ -29,16 +29,16 @@ MSSPTable = { "CRAWL DELAY": "-1", # limit how often crawler updates the listing. -1 for no limit - "HOSTNAME": "", # current or new hostname + "HOSTNAME": "", # current or new hostname "PORT": ["4000"], # most important port should be last in list "CODEBASE": "Evennia", "CONTACT": "", # email for contacting the mud "CREATED": "", # year MUD was created - "ICON": "", # url to icon 32x32 or larger; <32kb. + "ICON": "", # url to icon 32x32 or larger; <32kb. "IP": "", # current or new IP address "LANGUAGE": "", # name of language used, e.g. English "LOCATION": "", # full English name of server country - "MINIMUM AGE": "0", # set to 0 if not applicable + "MINIMUM AGE": "0", # set to 0 if not applicable "WEBSITE": "www.evennia.com", # Categorisation @@ -50,14 +50,14 @@ MSSPTable = { # Roleplaying, Simulation, Social or Strategy "STATUS": "Open Beta", # Alpha, Closed Beta, Open Beta, Live "GAMESYSTEM": "Custom", # D&D, d20 System, World of Darkness, etc. Use Custom if homebrew - "INTERMUD": "IMC2", # evennia supports IMC2. - "SUBGENRE": "None", # LASG, Medieval Fantasy, World War II, Frankenstein, + "INTERMUD": "IMC2", # evennia supports IMC2. + "SUBGENRE": "None", # LASG, Medieval Fantasy, World War II, Frankenstein, # Cyberpunk, Dragonlance, etc. Or None if not available. # World - "AREAS": "0", - "HELPFILES": "0", + "AREAS": "0", + "HELPFILES": "0", "MOBILES": "0", "OBJECTS": "0", "ROOMS": "0", # use 0 if room-less @@ -121,7 +121,7 @@ MSSPTable = { # Protocols (only change if you added/removed something manually) "ATCP": "0", - "MSDP": "0", + "MSDP": "0", "MCCP": "1", "SSL": "1", "UTF-8": "1", diff --git a/game/gamesrc/conf/examples/oobfuncs.py b/game/gamesrc/conf/examples/oobfuncs.py index 5638f48c1f..79b92e75a7 100644 --- a/game/gamesrc/conf/examples/oobfuncs.py +++ b/game/gamesrc/conf/examples/oobfuncs.py @@ -3,14 +3,14 @@ ** OBS This module is not yet used by Evennia ** Example module holding functions for out-of-band protocols to - import and map to given commands from the client. This module - is selected by settings.OOB_FUNC_MODULE. - + import and map to given commands from the client. This module + is selected by settings.OOB_FUNC_MODULE. + All functions defined global in this module will be available for the oob system to call. They will be called with a session/character - as first argument (depending on if the session is logged in or not), + as first argument (depending on if the session is logged in or not), following by any number of extra arguments. The return value will - be packed and returned to the oob protocol and can be on any form. + be packed and returned to the oob protocol and can be on any form. """ def testoob(character, *args, **kwargs): diff --git a/game/gamesrc/objects/examples/character.py b/game/gamesrc/objects/examples/character.py index a6ba8b72df..a04607df00 100644 --- a/game/gamesrc/objects/examples/character.py +++ b/game/gamesrc/objects/examples/character.py @@ -3,16 +3,16 @@ Template for Characters Copy this module up one level and name it as you like, then -use it as a template to create your own Character class. +use it as a template to create your own Character class. -To make new logins default to creating characters +To make new logins default to creating characters of your new type, change settings.BASE_CHARACTER_TYPECLASS to point to your new class, e.g. settings.BASE_CHARACTER_TYPECLASS = "game.gamesrc.objects.mychar.MyChar" Note that objects already created in the database will not notice -this change, you have to convert them manually e.g. with the +this change, you have to convert them manually e.g. with the @typeclass command. """ @@ -20,22 +20,21 @@ from ev import Character class ExampleCharacter(Character): """ - The Character is like any normal Object (see example/object.py for - a list of properties and methods), except it actually implements - some of its hook methods to do some work: - - at_basetype_setup - always assigns the default_cmdset to this object type - (important!)sets locks so character cannot be picked up + The Character is like any normal Object (see example/object.py for + a list of properties and methods), except it actually implements + some of its hook methods to do some work: + + at_basetype_setup - always assigns the default_cmdset to this object type + (important!)sets locks so character cannot be picked up and its commands only be called by itself, not anyone else. (to change things, use at_object_creation() instead) at_after_move - launches the "look" command at_disconnect - stores the current location, so the "unconnected" character - object does not need to stay on grid but can be given a - None-location while offline. + object does not need to stay on grid but can be given a + None-location while offline. at_post_login - retrieves the character's old location and puts it back on the grid with a "charname has connected" message echoed to the room """ - pass - + pass diff --git a/game/gamesrc/objects/examples/exit.py b/game/gamesrc/objects/examples/exit.py index 0a9f996990..d88ff56c98 100644 --- a/game/gamesrc/objects/examples/exit.py +++ b/game/gamesrc/objects/examples/exit.py @@ -12,7 +12,7 @@ your new class, e.g. settings.BASE_EXIT_TYPECLASS = "game.gamesrc.objects.myexit.MyExit" Note that objects already created in the database will not notice -this change, you have to convert them manually e.g. with the +this change, you have to convert them manually e.g. with the @typeclass command. """ @@ -21,8 +21,8 @@ from ev import Exit class ExampleExit(Exit): """ Exits are connectors between rooms. Exits are normal Objects except - they defines the 'destination' property. It also does work in the - following methods: + they defines the 'destination' property. It also does work in the + following methods: basetype_setup() - sets default exit locks (to change, use at_object_creation instead) at_cmdset_get() - this auto-creates and caches a command and a command set on itself @@ -33,11 +33,11 @@ class ExampleExit(Exit): go there") if exit traversal fails and an attribute err_traverse is not defined. - Relevant hooks to overload (compared to other types of Objects): + Relevant hooks to overload (compared to other types of Objects): at_before_traverse(traveller) - called just before traversing at_after_traverse(traveller, source_loc) - called just after traversing at_failed_traverse(traveller) - called if traversal failed for some reason. Will - not be called if the attribute 'err_traverse' is + not be called if the attribute 'err_traverse' is defined, in which case that will simply be echoed. """ pass diff --git a/game/gamesrc/objects/examples/object.py b/game/gamesrc/objects/examples/object.py index 95f58a294a..d2129dd098 100644 --- a/game/gamesrc/objects/examples/object.py +++ b/game/gamesrc/objects/examples/object.py @@ -3,7 +3,7 @@ Template for Objects Copy this module up one level and name it as you like, then -use it as a template to create your own Objects. +use it as a template to create your own Objects. To make the default commands default to creating objects of your new type (and also change the "fallback" object used when typeclass @@ -13,7 +13,7 @@ your new class, e.g. settings.BASE_OBJECT_TYPECLASS = "game.gamesrc.objects.myobj.MyObj" Note that objects already created in the database will not notice -this change, you have to convert them manually e.g. with the +this change, you have to convert them manually e.g. with the @typeclass command. """ @@ -34,19 +34,19 @@ class ExampleObject(Object): methods, such as __init__ and especially never __getattribute__ and __setattr__ since these are used heavily by the typeclass system of Evennia and messing with them might well break things for you. - - * Base properties defined/available on all Objects - key (string) - name of object + * Base properties defined/available on all Objects + + 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 home (Object) - safety start-location @@ -54,19 +54,19 @@ class ExampleObject(Object): 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) @@ -79,21 +79,21 @@ class ExampleObject(Object): swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) access(accessing_obj, access_type='read', default=False) check_permstring(permstring) - - * Hooks (these are class methods, so their arguments should also start with self): + + * Hooks (these are class methods, so their arguments should also start with self): 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 , they don't need to be removed here. + inside a deleted object are automatically moved to their , 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 @@ -106,15 +106,15 @@ class ExampleObject(Object): 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 diff --git a/game/gamesrc/objects/examples/player.py b/game/gamesrc/objects/examples/player.py index e3de1e2d32..d5b48a88f7 100644 --- a/game/gamesrc/objects/examples/player.py +++ b/game/gamesrc/objects/examples/player.py @@ -3,16 +3,16 @@ Template module for Players Copy this module up one level and name it as you like, then -use it as a template to create your own Player class. +use it as a template to create your own Player class. -To make the default account login default to using a Player +To make the default account login default to using a Player of your new type, change settings.BASE_PLAYER_TYPECLASS to point to your new class, e.g. settings.BASE_PLAYER_TYPECLASS = "game.gamesrc.objects.myplayer.MyPlayer" Note that objects already created in the database will not notice -this change, you have to convert them manually e.g. with the +this change, you have to convert them manually e.g. with the @typeclass command. """ @@ -20,19 +20,19 @@ from ev import Player class ExamplePlayer(Player): """ - This class describes the actual OOC player (i.e. the user connecting + 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. - - It can be useful e.g. for storing configuration options for your game, but + are attended/joined using this object. + + It can be useful e.g. for storing configuration options for your game, but should generally not hold any character-related info (that's best handled on the character level). Can be set using BASE_PLAYER_TYPECLASS. - * available properties + * available properties key (string) - name of player name (string)- wrapper for user.username @@ -41,18 +41,18 @@ class ExamplePlayer(Player): dbobj (Player, read-only) - link to database model. dbobj.typeclass points back to this class typeclass (Player, 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 user (User, read-only) - django User authorization object obj (Object) - game object controlled by player. 'character' can also be used. sessions (list of Sessions) - sessions connected to this player is_superuser (bool, read-only) - if the connected user is a superuser - * Handlers + * Handlers 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(). @@ -71,12 +71,12 @@ class ExamplePlayer(Player): * Hook methods (when re-implementation, remember methods need to have self as first arg) basetype_setup() - at_player_creation() + at_player_creation() - note that the following hooks are also found on Objects and are usually handled on the character level: - at_init() + at_init() at_cmdset_get() at_first_login() at_post_login() diff --git a/game/gamesrc/objects/examples/red_button.py b/game/gamesrc/objects/examples/red_button.py index 7663561dfc..ef8acb2ec5 100644 --- a/game/gamesrc/objects/examples/red_button.py +++ b/game/gamesrc/objects/examples/red_button.py @@ -4,13 +4,13 @@ This is a more advanced example object. It combines functions from script.examples as well as commands.examples to make an interactive button typeclass. -Create this button with +Create this button with - @create/drop examples.red_button.RedButton + @create/drop examples.red_button.RedButton -Note that if you must drop the button before you can see its messages! +Note that if you must drop the button before you can see its messages! """ -import random +import random from ev import Object from game.gamesrc.scripts.examples import red_button_scripts as scriptexamples from game.gamesrc.commands.examples import cmdset_red_button as cmdsetexamples @@ -18,7 +18,7 @@ from game.gamesrc.commands.examples import cmdset_red_button as cmdsetexamples # # Definition of the object itself # - + class RedButton(Object): """ This class describes an evil red button. It will use the script @@ -36,30 +36,30 @@ class RedButton(Object): """ This function is called when object is created. Use this instead of e.g. __init__. - """ + """ # store desc (default, you can change this at creation time) desc = "This is a large red button, inviting yet evil-looking. " - desc += "A closed glass lid protects it." - self.db.desc = desc + desc += "A closed glass lid protects it." + self.db.desc = desc - # We have to define all the variables the scripts - # are checking/using *before* adding the scripts or - # they might be deactivated before even starting! - self.db.lid_open = False - self.db.lamp_works = True + # We have to define all the variables the scripts + # are checking/using *before* adding the scripts or + # they might be deactivated before even starting! + self.db.lid_open = False + self.db.lamp_works = True self.db.lid_locked = False self.cmdset.add_default(cmdsetexamples.DefaultCmdSet, permanent=True) # since the cmdsets relevant to the button are added 'on the fly', # we need to setup custom scripts to do this for us (also, these scripts - # check so they are valid (i.e. the lid is actually still closed)). - # The AddClosedCmdSet script makes sure to add the Closed-cmdset. + # check so they are valid (i.e. the lid is actually still closed)). + # The AddClosedCmdSet script makes sure to add the Closed-cmdset. self.scripts.add(scriptexamples.ClosedLidState) # the script EventBlinkButton makes the button blink regularly. self.scripts.add(scriptexamples.BlinkButtonEvent) - # state-changing methods + # state-changing methods def open_lid(self): """ @@ -68,12 +68,12 @@ class RedButton(Object): """ if self.db.lid_open: - return + return desc = self.db.desc_lid_open if not desc: desc = "This is a large red button, inviting yet evil-looking. " desc += "Its glass cover is open and the button exposed." - self.db.desc = desc + self.db.desc = desc self.db.lid_open = True # with the lid open, we validate scripts; this will clean out @@ -93,13 +93,13 @@ class RedButton(Object): """ if not self.db.lid_open: - return + return desc = self.db.desc_lid_closed if not desc: desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is closed, protecting it." - self.db.desc = desc - self.db.lid_open = False + desc += "Its glass cover is closed, protecting it." + self.db.desc = desc + self.db.lid_open = False # clean out scripts depending on lid to be open self.scripts.validate() @@ -109,17 +109,17 @@ class RedButton(Object): def break_lamp(self, feedback=True): """ Breaks the lamp in the button, stopping it from blinking. - + """ - self.db.lamp_works = False + self.db.lamp_works = False desc = self.db.desc_lamp_broken - if not desc: + if not desc: self.db.desc += "\nThe big red button has stopped blinking for the time being." else: self.db.desc = desc if feedback and self.location: - self.location.msg_contents("The lamp flickers, the button going dark.") + self.location.msg_contents("The lamp flickers, the button going dark.") self.scripts.validate() def press_button(self, pobject): @@ -129,7 +129,7 @@ class RedButton(Object): """ # deactivate the button so it won't flash/close lid etc. self.scripts.add(scriptexamples.DeactivateButtonEvent) - # blind the person pressing the button. Note that this + # blind the person pressing the button. Note that this # script is set on the *character* pressing the button! pobject.scripts.add(scriptexamples.BlindedState) @@ -140,19 +140,18 @@ class RedButton(Object): The script system will regularly call this function to make the button blink. Now and then it won't blink at all though, to add some randomness - to how often the message is echoed. + to how often the message is echoed. """ - loc = self.location - if loc: + loc = self.location + if loc: rand = random.random() - if rand < 0.2: + if rand < 0.2: string = "The red button flashes briefly." elif rand < 0.4: string = "The red button blinks invitingly." elif rand < 0.6: - string = "The red button flashes. You know you wanna push it!" + string = "The red button flashes. You know you wanna push it!" else: # no blink - return + return loc.msg_contents(string) - diff --git a/game/gamesrc/objects/examples/room.py b/game/gamesrc/objects/examples/room.py index 852be40ba3..ff54f7d375 100644 --- a/game/gamesrc/objects/examples/room.py +++ b/game/gamesrc/objects/examples/room.py @@ -3,7 +3,7 @@ Template module for Rooms Copy this module up one level and name it as you like, then -use it as a template to create your own Objects. +use it as a template to create your own Objects. To make the default commands (such as @dig) default to creating rooms of your new type, change settings.BASE_ROOM_TYPECLASS to point to @@ -12,7 +12,7 @@ your new class, e.g. settings.BASE_ROOM_TYPECLASS = "game.gamesrc.objects.myroom.MyRoom" Note that objects already created in the database will not notice -this change, you have to convert them manually e.g. with the +this change, you have to convert them manually e.g. with the @typeclass command. """ @@ -22,11 +22,11 @@ from ev import Room class ExampleRoom(Room): """ Rooms are like any Object, except their location is None - (which is default). They also use basetype_setup() to + (which is default). They also use basetype_setup() to add locks so they cannot be puppeted or picked up. (to change that, use at_object_creation instead) See examples/object.py for a list of - properties and methods available on all Objects. + properties and methods available on all Objects. """ pass diff --git a/game/gamesrc/scripts/examples/bodyfunctions.py b/game/gamesrc/scripts/examples/bodyfunctions.py index 4c4d6f7b6f..8dd5d805b2 100644 --- a/game/gamesrc/scripts/examples/bodyfunctions.py +++ b/game/gamesrc/scripts/examples/bodyfunctions.py @@ -1,9 +1,9 @@ """ Example script for testing. This adds a simple timer that has your character make observations and noices at irregular -intervals. +intervals. -To test, use +To test, use @script me = examples.bodyfunctions.BodyFunctions The script will only send messages to the object it @@ -11,7 +11,7 @@ is stored on, so make sure to put it on yourself or you won't see any messages! """ -import random +import random from ev import Script class BodyFunctions(Script): @@ -19,26 +19,26 @@ class BodyFunctions(Script): This class defines the script itself """ - def at_script_creation(self): + def at_script_creation(self): self.key = "bodyfunction" self.desc = "Adds various timed events to a character." self.interval = 20 # seconds #self.repeats = 5 # repeat only a certain number of times self.start_delay = True # wait self.interval until first call #self.persistent = True - + def at_repeat(self): """ - This gets called every self.interval seconds. We make - a random check here so as to only return 33% of the time. + This gets called every self.interval seconds. We make + a random check here so as to only return 33% of the time. """ - + if random.random() < 0.66: # no message this time - return + return rand = random.random() # return a random message - if rand < 0.1: + if rand < 0.1: string = "You tap your foot, looking around." elif rand < 0.2: string = "You have an itch. Hard to reach too." @@ -58,6 +58,6 @@ class BodyFunctions(Script): string = "You get a great idea. Of course you won't tell anyone." else: string = "You suddenly realize how much you love Evennia!" - + # echo the message to the object self.obj.msg(string) diff --git a/game/gamesrc/scripts/examples/red_button_scripts.py b/game/gamesrc/scripts/examples/red_button_scripts.py index f935ac3458..9208a7e1c2 100644 --- a/game/gamesrc/scripts/examples/red_button_scripts.py +++ b/game/gamesrc/scripts/examples/red_button_scripts.py @@ -1,7 +1,7 @@ """ Example of scripts. -These are scripts intended for a particular object - the +These are scripts intended for a particular object - the red_button object type in gamesrc/types/examples. A few variations on uses of scripts are included. @@ -11,45 +11,45 @@ from game.gamesrc.commands.examples import cmdset_red_button as cmdsetexamples # # Scripts as state-managers -# +# # Scripts have many uses, one of which is to statically # make changes when a particular state of an object changes. # There is no "timer" involved in this case (although there could be), # whenever the script determines it is "invalid", it simply shuts down -# along with all the things it controls. -# +# along with all the things it controls. +# # To show as many features as possible of the script and cmdset systems, # we will use three scripts controlling one state each of the red_button, -# each with its own set of commands, handled by cmdsets - one for when +# each with its own set of commands, handled by cmdsets - one for when # the button has its lid open, and one for when it is closed and a # last one for when the player pushed the button and gets blinded by # a bright light. The last one also has a timer component that allows it -# to remove itself after a while (and the player recovers their eyesight). +# to remove itself after a while (and the player recovers their eyesight). class ClosedLidState(Script): """ - This manages the cmdset for the "closed" button state. What this + This manages the cmdset for the "closed" button state. What this means is that while this script is valid, we add the RedButtonClosed cmdset to it (with commands like open, nudge lid etc) """ def at_script_creation(self): "Called when script first created." self.desc = "Script that manages the closed-state cmdsets for red button." - self.persistent = True + self.persistent = True def at_start(self): """ This is called once every server restart, so we want to add the (memory-resident) cmdset to the object here. is_valid is automatically checked so we don't need to worry about adding the script to an - open lid. + open lid. """ #All we do is add the cmdset for the closed state. self.obj.cmdset.add(cmdsetexamples.LidClosedCmdSet) - + def is_valid(self): """ - The script is only valid while the lid is closed. + The script is only valid while the lid is closed. self.obj is the red_button on which this script is defined. """ return not self.obj.db.lid_open @@ -57,7 +57,7 @@ class ClosedLidState(Script): def at_stop(self): """ When the script stops we must make sure to clean up after us. - + """ self.obj.cmdset.delete(cmdsetexamples.LidClosedCmdSet) @@ -68,23 +68,23 @@ class OpenLidState(Script): the RedButtonOpen """ def at_script_creation(self): - "Called when script first created." + "Called when script first created." self.desc = "Script that manages the opened-state cmdsets for red button." - self.persistent = True + self.persistent = True def at_start(self): """ This is called once every server restart, so we want to add the - (memory-resident) cmdset to the object here. is_valid is - automatically checked, so we don't need to worry about + (memory-resident) cmdset to the object here. is_valid is + automatically checked, so we don't need to worry about adding the cmdset to a closed lid-button. """ #print "In Open at_start (should add cmdset)" self.obj.cmdset.add(cmdsetexamples.LidOpenCmdSet) - + def is_valid(self): """ - The script is only valid while the lid is open. + The script is only valid while the lid is open. self.obj is the red_button on which this script is defined. """ return self.obj.db.lid_open @@ -99,12 +99,12 @@ class OpenLidState(Script): class BlindedState(Script): """ - This is a timed state. + This is a timed state. This adds a (very limited) cmdset TO THE PLAYER, during a certain time, - after which the script will close and all functions are + after which the script will close and all functions are restored. It's up to the function starting the script to actually - set it on the right player object. + set it on the right player object. """ def at_script_creation(self): """ @@ -114,13 +114,13 @@ class BlindedState(Script): self.desc = "Temporarily blinds the player for a little while." self.interval = 20 # seconds self.start_delay = True # we don't want it to stop until after 20s. - self.repeats = 1 # this will go away after interval seconds. + self.repeats = 1 # this will go away after interval seconds. self.persistent = False # we will ditch this if server goes down def at_start(self): """ We want to add the cmdset to the linked object. - + Note that the RedButtonBlind cmdset is defined to completly replace the other cmdsets on the stack while it is active (this means that while blinded, only operations in this cmdset @@ -133,39 +133,39 @@ class BlindedState(Script): def at_stop(self): """ It's important that we clear out that blinded cmdset - when we are done! + when we are done! """ self.obj.msg("You blink feverishly as your eyesight slowly returns.") - self.obj.location.msg_contents("%s seems to be recovering their eyesight." - % self.obj.name, + self.obj.location.msg_contents("%s seems to be recovering their eyesight." + % self.obj.name, exclude=self.obj) - self.obj.cmdset.delete() # this will clear the latest added cmdset, + self.obj.cmdset.delete() # this will clear the latest added cmdset, # (which is the blinded one). # # Timer/Event-like Scripts # -# Scripts can also work like timers, or "events". Below we +# Scripts can also work like timers, or "events". Below we # define three such timed events that makes the button a little -# more "alive" - one that makes the button blink menacingly, another -# that makes the lid covering the button slide back after a while. +# more "alive" - one that makes the button blink menacingly, another +# that makes the lid covering the button slide back after a while. # class CloseLidEvent(Script): """ This event closes the glass lid over the button some time after it was opened. It's a one-off - script that should be started/created when the - lid is opened. + script that should be started/created when the + lid is opened. """ def at_script_creation(self): """ Called when script object is first created. Sets things up. We want to have a lid on the button that the user can pull - aside in order to make the button 'pressable'. But after a set + aside in order to make the button 'pressable'. But after a set time that lid should auto-close again, making the button safe - from pressing (and deleting this command). + from pressing (and deleting this command). """ self.key = "lid_closer" self.desc = "Closes lid on a red buttons" @@ -177,61 +177,61 @@ class CloseLidEvent(Script): def is_valid(self): """ - This script can only operate if the lid is open; if it + This script can only operate if the lid is open; if it is already closed, the script is clearly invalid. - + Note that we are here relying on an self.obj being - defined (and being a RedButton object) - this we should be able to - expect since this type of script is always tied to one individual + defined (and being a RedButton object) - this we should be able to + expect since this type of script is always tied to one individual red button object and not having it would be an error. """ return self.obj.db.lid_open def at_repeat(self): """ - Called after self.interval seconds. It closes the lid. Before this method is - called, self.is_valid() is automatically checked, so there is no need to + Called after self.interval seconds. It closes the lid. Before this method is + called, self.is_valid() is automatically checked, so there is no need to check this manually. """ self.obj.close_lid() class BlinkButtonEvent(Script): - """ - This timed script lets the button flash at regular intervals. + """ + This timed script lets the button flash at regular intervals. """ def at_script_creation(self): """ - Sets things up. We want the button's lamp to blink at + Sets things up. We want the button's lamp to blink at regular intervals, unless it's broken (can happen - if you try to smash the glass, say). + if you try to smash the glass, say). """ self.key = "blink_button" self.desc = "Blinks red buttons" self.interval = 35 #seconds self.start_delay = False #blink right away self.persistent = True #keep blinking also after server reboot - + def is_valid(self): """ Button will keep blinking unless it is broken. """ #print "self.obj.db.lamp_works:", self.obj.db.lamp_works return self.obj.db.lamp_works - + def at_repeat(self): """ - Called every self.interval seconds. Makes the lamp in + Called every self.interval seconds. Makes the lamp in the button blink. """ self.obj.blink() class DeactivateButtonEvent(Script): """ - This deactivates the button for a short while (it won't blink, won't + This deactivates the button for a short while (it won't blink, won't close its lid etc). It is meant to be called when the button is pushed and run as long as the blinded effect lasts. We cannot put these methods in the AddBlindedCmdSet script since that script is defined on the *player* - whereas this one must be defined on the *button*. + whereas this one must be defined on the *button*. """ def at_script_creation(self): """ @@ -241,9 +241,9 @@ class DeactivateButtonEvent(Script): self.desc = "Deactivate red button temporarily" self.interval = 21 #seconds self.start_delay = True # wait with the first repeat for self.interval seconds. - self.persistent = True + self.persistent = True self.repeats = 1 # only do this once - + def at_start(self): """ Deactivate the button. Observe that this method is always @@ -252,9 +252,9 @@ class DeactivateButtonEvent(Script): """ # closing the lid will also add the ClosedState script self.obj.close_lid() - # lock the lid so other players can't access it until the + # lock the lid so other players can't access it until the # first one's effect has worn off. - self.obj.db.lid_locked = True + self.obj.db.lid_locked = True # breaking the lamp also sets a correct desc self.obj.break_lamp(feedback=False) @@ -263,11 +263,11 @@ class DeactivateButtonEvent(Script): When this is called, reset the functionality of the button. """ # restore button's desc. - + self.obj.db.lamp_works = True desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is closed, protecting it." - self.db.desc = desc + desc += "Its glass cover is closed, protecting it." + self.db.desc = desc # re-activate the blink button event. self.obj.scripts.add(BlinkButtonEvent) # unlock the lid diff --git a/game/gamesrc/scripts/examples/script.py b/game/gamesrc/scripts/examples/script.py index 99a3cd206a..30e4b9db56 100644 --- a/game/gamesrc/scripts/examples/script.py +++ b/game/gamesrc/scripts/examples/script.py @@ -1,6 +1,6 @@ """ -Template module for Scripts +Template module for Scripts Copy this module up one level to gamesrc/scripts and name it appropriately, then use that as a template to create your own script. @@ -13,10 +13,10 @@ Scripts are objects that handle everything in the game having a time-component (i.e. that may change with time, with or without a player being involved in the change). Scripts can work like "events", in that they are triggered at regular intervals to do a certain script, -but an Script set on an object can also be responsible for silently +but an Script set on an object can also be responsible for silently checking if its state changes, so as to update it. Evennia use several in-built scripts to keep track of things like time, to clean out -dropped connections etc. +dropped connections etc. """ @@ -26,32 +26,32 @@ class ExampleScript(BaseScript): """ A script type is customized by redefining some or all of its hook methods and variables. - * available properties + * available properties - 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 desc (string) - optional description of script, shown in listings - obj (Object) - optional object that this script is connected to and acts on (set automatically by obj.scripts.add()) + obj (Object) - optional object that this script is connected to and acts on (set automatically by obj.scripts.add()) interval (int) - how often script should run, in seconds. <0 turns off ticker start_delay (bool) - if the script should start repeating right away or wait self.interval seconds repeats (int) - how many times the script should repeat before stopping. 0 means infinite repeats persistent (bool) - if script should survive a server shutdown or not - is_active (bool) - if script is currently running + is_active (bool) - if script is currently running * Handlers 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 - * Helper methods + * Helper methods start() - start script (this usually happens automatically at creation and obj.script.add() etc) stop() - stop script, and delete it @@ -66,22 +66,22 @@ class ExampleScript(BaseScript): is_valid() - is called to check if the script is valid to be running at the current time. If is_valid() returns False, the running script is stopped and removed from the game. You can use this - to check state changes (i.e. an script tracking some combat - stats at regular intervals is only valid to run while there is - actual combat going on). + to check state changes (i.e. an script tracking some combat + stats at regular intervals is only valid to run while there is + actual combat going on). at_start() - Called every time the script is started, which for persistent scripts is at least once every server start. Note that this is unaffected by self.delay_start, which only delays the first call - to at_repeat(). + to at_repeat(). at_repeat() - Called every self.interval seconds. It will be called immediately upon launch unless self.delay_start is True, which will delay - the first call of this method by self.interval seconds. If - self.interval==0, this method will never be called. + the first call of this method by self.interval seconds. If + self.interval==0, this method will never be called. at_stop() - Called as the script object is stopped and is about to be removed from the game, e.g. because is_valid() returned False. - at_server_reload() - Called when server reloads. Can be used to save temporary + at_server_reload() - Called when server reloads. Can be used to save temporary variables you want should survive a reload. - at_server_shutdown() - called at a full server shutdown. + at_server_shutdown() - called at a full server shutdown. """ - pass + pass diff --git a/game/gamesrc/world/examples/batch_cmds.ev b/game/gamesrc/world/examples/batch_cmds.ev index 60416db0ba..fe8d4dd9f6 100644 --- a/game/gamesrc/world/examples/batch_cmds.ev +++ b/game/gamesrc/world/examples/batch_cmds.ev @@ -1,5 +1,5 @@ # -# This is an example batch build file for Evennia. +# This is an example batch build file for Evennia. # # It allows batch processing of normal Evennia commands. # Test it by loading it with the @batchprocess command @@ -10,9 +10,9 @@ # marks the end of a previous command definition (important!). # # All supplied commands are given as normal, on their own line -# and accepts arguments in any format up until the first next +# and accepts arguments in any format up until the first next # comment line begins. Extra whitespace is removed; an empty -# line in a command definition translates into a newline. +# line in a command definition translates into a newline. # # This creates a red button @@ -20,32 +20,32 @@ @create button:examples.red_button.RedButton # This comment ends input for @create -# Next command: +# Next command: -@set button/desc = - This is a large red button. Now and then - it flashes in an evil, yet strangely tantalizing way. +@set button/desc = + This is a large red button. Now and then + it flashes in an evil, yet strangely tantalizing way. A big sign sits next to it. It says: ----------- - Press me! + Press me! ----------- - ... It really begs to be pressed, doesn't it? You -know you want to! - -# This ends the @set command. Note that line breaks and extra spaces -# in the argument are not considered. A completely empty line + ... It really begs to be pressed, doesn't it? You +know you want to! + +# This ends the @set command. Note that line breaks and extra spaces +# in the argument are not considered. A completely empty line # translates to a \n newline in the command; two empty lines will thus # create a new paragraph. (note that few commands support it though, you # mainly want to use it for descriptions) -# Now let's place the button where it belongs (let's say limbo #2 is +# Now let's place the button where it belongs (let's say limbo #2 is # the evil lair in our example) @teleport #2 diff --git a/game/gamesrc/world/examples/batch_code.py b/game/gamesrc/world/examples/batch_code.py index 8bfd7ee217..cd9ecc38ce 100644 --- a/game/gamesrc/world/examples/batch_code.py +++ b/game/gamesrc/world/examples/batch_code.py @@ -1,6 +1,6 @@ # # Batchcode script -# +# # # The Batch-code processor accepts full python modules (e.g. "batch.py") that # looks identical to normal Python files with a few exceptions that allows them @@ -8,29 +8,29 @@ # of the file and allows for features like stepping from block to block # (without executing those coming before), as well as automatic deletion # of created objects etc. You can however also run a batch-code python file -# directly using Python (and can also be de). +# directly using Python (and can also be de). -# Code blocks are separated by python comments starting with special code words. +# Code blocks are separated by python comments starting with special code words. # #HEADER - this denotes commands global to the entire file, such as # import statements and global variables. They will # automatically be made available for each block. Observe # that changes to these variables made in one block is not # preserved between blocks!) -# #CODE (infotext) [objname, objname, ...] - This designates a code block that will be executed like a +# #CODE (infotext) [objname, objname, ...] - This designates a code block that will be executed like a # stand-alone piece of code together with any #HEADER -# defined. -# infotext is a describing text about what goes in in this block. It will be +# defined. +# infotext is a describing text about what goes in in this block. It will be # shown by the batchprocessing command. -# s mark the (variable-)names of objects created in the code, -# and which may be auto-deleted by the processor if desired (such as when -# debugging the script). E.g., if the code contains the command +# s mark the (variable-)names of objects created in the code, +# and which may be auto-deleted by the processor if desired (such as when +# debugging the script). E.g., if the code contains the command # myobj = create.create_object(...), you could put 'myobj' in the #CODE header -# regardless of what the created object is actually called in-game. -# #INSERT filename - this includes another code batch file. The named file will be loaded and +# regardless of what the created object is actually called in-game. +# #INSERT filename - this includes another code batch file. The named file will be loaded and # run at this point. Note that code from the inserted file will NOT share #HEADERs # with the importing file, but will only use the headers in the importing file. -# make sure to not create a cyclic import here! +# make sure to not create a cyclic import here! # The following variable is automatically made available for the script: @@ -38,9 +38,9 @@ # -#HEADER +#HEADER -# everything in this block will be appended to the beginning of +# everything in this block will be appended to the beginning of # all other #CODE blocks when they are executed. from ev import create, search @@ -53,13 +53,13 @@ limbo = search.objects('Limbo', global_search=True)[0] #CODE (create red button) # This is the first code block. Within each block, python -# code works as normal. Note how we make use if imports and +# code works as normal. Note how we make use if imports and # 'limbo' defined in the #HEADER block. This block's header -# offers no information about red_button variable, so it -# won't be able to be deleted in debug mode. +# offers no information about red_button variable, so it +# won't be able to be deleted in debug mode. # create a red button in limbo -red_button = create.create_object(red_button.RedButton, key="Red button", +red_button = create.create_object(red_button.RedButton, key="Red button", location=limbo, aliases=["button"]) # we take a look at what we created @@ -74,10 +74,10 @@ caller.msg("A %s was created." % red_button.key) # times). # the python variables we assign to must match the ones given in the -# header for the system to be able to delete them afterwards during a -# debugging run. +# header for the system to be able to delete them afterwards during a +# debugging run. table = create.create_object(baseobjects.Object, key="Table", location=limbo) chair = create.create_object(baseobjects.Object, key="Chair", location=limbo) -string = "A %s and %s were created. If debug was active, they were deleted again." +string = "A %s and %s were created. If debug was active, they were deleted again." caller.msg(string % (table, chair)) diff --git a/game/manage.py b/game/manage.py index f3598063cd..e93e3b76d2 100755 --- a/game/manage.py +++ b/game/manage.py @@ -2,7 +2,7 @@ """ Set up the evennia system. A first startup consists of giving the command './manage syncdb' to setup the system and create -the database. +the database. """ import sys @@ -21,10 +21,10 @@ except IOError: VERSION = "Unknown version" #------------------------------------------------------------ -# Check so session file exists in the current dir- if not, create it. +# Check so session file exists in the current dir- if not, create it. #------------------------------------------------------------ -_CREATED_SETTINGS = False +_CREATED_SETTINGS = False if not os.path.exists('settings.py'): # If settings.py doesn't already exist, create it and populate it with some # basic stuff. @@ -33,7 +33,7 @@ if not os.path.exists('settings.py'): _CREATED_SETTINGS = True string = \ - """# + """# # Evennia MU* server configuration file # # You may customize your setup by copy&pasting the variables you want @@ -44,14 +44,14 @@ if not os.path.exists('settings.py'): # (also, the master config file may change with server updates). # -from src.settings_default import * +from src.settings_default import * ################################################### -# Evennia base server config +# Evennia base server config ################################################### ################################################### -# Evennia Database config +# Evennia Database config ################################################### ################################################### @@ -59,15 +59,15 @@ from src.settings_default import * ################################################### ################################################### -# Default command sets +# Default command sets ################################################### ################################################### -# Typeclasses +# Typeclasses ################################################### ################################################### -# Batch processors +# Batch processors ################################################### ################################################### @@ -100,8 +100,8 @@ from src.settings_default import * # obs - this string cannot be under i18n since settings didn't exist yet. print """ - Welcome to Evennia (version %(version)s)! - We created a fresh settings.py file for you.""" % {'version': VERSION} + Welcome to Evennia (version %(version)s)! + We created a fresh settings.py file for you.""" % {'version': VERSION} #------------------------------------------------------------ @@ -118,18 +118,18 @@ except Exception: # note - if this fails, ugettext will also fail, so we cannot translate this string. string += """\n - Error: Couldn't import the file 'settings.py' in the directory - containing %(file)r. There are usually two reasons for this: - 1) You moved your settings.py elsewhere. In that case move it back or - create a link to it from this folder. + Error: Couldn't import the file 'settings.py' in the directory + containing %(file)r. There are usually two reasons for this: + 1) You moved your settings.py elsewhere. In that case move it back or + create a link to it from this folder. 2) The settings module is where it's supposed to be, but contains errors. - Review the traceback above to resolve the problem, then try again. - 3) If you get errors on finding DJANGO_SETTINGS_MODULE you might have + Review the traceback above to resolve the problem, then try again. + 3) If you get errors on finding DJANGO_SETTINGS_MODULE you might have set up django wrong in some way. If you run a virtual machine, it might be worth - to restart it to see if this resolves the issue. Evennia should not require you - to define any environment variables manually. - """ % {'file': __file__} - print string + to restart it to see if this resolves the issue. Evennia should not require you + to define any environment variables manually. + """ % {'file': __file__} + print string sys.exit(1) os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings' @@ -139,8 +139,8 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings' #------------------------------------------------------------ if __name__ == "__main__": - # checks if the settings file was created this run - if _CREATED_SETTINGS: + # checks if the settings file was created this run + if _CREATED_SETTINGS: print _(""" Edit your new settings.py file as needed, then run 'python manage syncdb' and follow the prompts to @@ -149,7 +149,7 @@ if __name__ == "__main__": sys.exit() # run the standard django manager, if dependencies match - from src.utils.utils import check_evennia_dependencies + from src.utils.utils import check_evennia_dependencies if check_evennia_dependencies(): - from django.core.management import execute_manager + from django.core.management import execute_manager execute_manager(settings) diff --git a/game/runner.py b/game/runner.py index 46f6fbb220..1835bcc7d0 100644 --- a/game/runner.py +++ b/game/runner.py @@ -14,7 +14,7 @@ upon returning, or not. A process returning != 0 will always stop, no matter the value of this file. """ -import os +import os import sys from optparse import OptionParser from subprocess import Popen, call @@ -22,7 +22,7 @@ import Queue, thread, subprocess # # System Configuration -# +# SERVER_PIDFILE = "server.pid" @@ -39,7 +39,7 @@ if not os.path.exists('settings.py'): print "No settings.py file found. Run evennia.py to create it." sys.exit() - + # Get the settings from django.conf import settings @@ -58,26 +58,26 @@ if 'PYTHONPATH' in os.environ: else: os.environ['PYTHONPATH'] = currpath -TWISTED_BINARY = 'twistd' +TWISTED_BINARY = 'twistd' if os.name == 'nt': TWISTED_BINARY = 'twistd.bat' - err = False + err = False try: import win32api # Test for for win32api except ImportError: - err = True + err = True if not os.path.exists(TWISTED_BINARY): - err = True + err = True if err: print "Twisted binary for Windows is not ready to use. Please run evennia.py." sys.exit() -# Functions +# Functions def set_restart_mode(restart_file, flag=True): """ - This sets a flag file for the restart mode. - """ + This sets a flag file for the restart mode. + """ f = open(restart_file, 'w') f.write(str(flag)) f.close() @@ -89,24 +89,24 @@ def get_restart_mode(restart_file): if os.path.exists(restart_file): flag = open(restart_file, 'r').read() return flag == "True" - return False + return False def get_pid(pidfile): """ Get the PID (Process ID) by trying to access - an PID file. + an PID file. """ - pid = None + pid = None if os.path.exists(pidfile): f = open(pidfile, 'r') pid = f.read() - return pid + return pid def cycle_logfile(logfile): """ Move the old log files to .old - """ + """ logfile_old = logfile + '.old' if os.path.exists(logfile): # Cycle the old logfiles to *.old @@ -122,70 +122,70 @@ def cycle_logfile(logfile): if os.path.exists(logfile_old): # E.g. Windows don't support rename-replace os.remove(logfile_old) - os.rename(logfile, logfile_old) + os.rename(logfile, logfile_old) -# Start program management +# Start program management SERVER = None -PORTAL = None +PORTAL = None def start_services(server_argv, portal_argv): """ This calls a threaded loop that launces the Portal and Server - and then restarts them when they finish. + and then restarts them when they finish. """ - global SERVER, PORTAL + global SERVER, PORTAL processes = Queue.Queue() - def server_waiter(queue): - try: + def server_waiter(queue): + try: rc = Popen(server_argv).wait() except Exception, e: print "Server process error: %(e)s" % {'e': e} queue.put(("server_stopped", rc)) # this signals the controller that the program finished - def portal_waiter(queue): - try: + def portal_waiter(queue): + try: rc = Popen(portal_argv).wait() except Exception, e: print "Portal process error: %(e)s" % {'e': e} queue.put(("portal_stopped", rc)) # this signals the controller that the program finished - + if server_argv: - # start server as a reloadable thread + # start server as a reloadable thread SERVER = thread.start_new_thread(server_waiter, (processes, )) - if portal_argv: + if portal_argv: if get_restart_mode(PORTAL_RESTART): - # start portal as interactive, reloadable thread + # start portal as interactive, reloadable thread PORTAL = thread.start_new_thread(portal_waiter, (processes, )) else: # normal operation: start portal as a daemon; we don't care to monitor it for restart PORTAL = Popen(portal_argv) if not SERVER: # if portal is daemon and no server is running, we have no reason to continue to the loop. - return + return - # Reload loop + # Reload loop while True: - + # this blocks until something is actually returned. - message, rc = processes.get() + message, rc = processes.get() # restart only if process stopped cleanly if message == "server_stopped" and int(rc) == 0 and get_restart_mode(SERVER_RESTART): - print "Evennia Server stopped. Restarting ..." + print "Evennia Server stopped. Restarting ..." SERVER = thread.start_new_thread(server_waiter, (processes, )) - continue + continue # normally the portal is not reloaded since it's run as a daemon. if message == "portal_stopped" and int(rc) == 0 and get_restart_mode(PORTAL_RESTART): print "Evennia Portal stopped in interactive mode. Restarting ..." - PORTAL = thread.start_new_thread(portal_waiter, (processes, )) - continue - break + PORTAL = thread.start_new_thread(portal_waiter, (processes, )) + continue + break # Setup signal handling @@ -193,19 +193,19 @@ def main(): """ This handles the command line input of the runner (it's most often called by evennia.py) """ - + parser = OptionParser(usage="%prog [options] start", description="This runner should normally *not* be called directly - it is called automatically from the evennia.py main program. It manages the Evennia game server and portal processes an hosts a threaded loop to restart the Server whenever it is stopped (this constitues Evennia's reload mechanism).") - parser.add_option('-s', '--noserver', action='store_true', + parser.add_option('-s', '--noserver', action='store_true', dest='noserver', default=False, help='Do not start Server process') - parser.add_option('-p', '--noportal', action='store_true', + parser.add_option('-p', '--noportal', action='store_true', dest='noportal', default=False, help='Do not start Portal process') - parser.add_option('-i', '--iserver', action='store_true', + parser.add_option('-i', '--iserver', action='store_true', dest='iserver', default=False, help='output server log to stdout instead of logfile') - parser.add_option('-d', '--iportal', action='store_true', + parser.add_option('-d', '--iportal', action='store_true', dest='iportal', default=False, help='output portal log to stdout. Does not make portal a daemon.') parser.add_option('-S', '--profile-server', action='store_true', @@ -222,17 +222,17 @@ def main(): parser.print_help() sys.exit() - # set up default project calls - server_argv = [TWISTED_BINARY, + # set up default project calls + server_argv = [TWISTED_BINARY, '--nodaemon', '--logfile=%s' % SERVER_LOGFILE, - '--pidfile=%s' % SERVER_PIDFILE, + '--pidfile=%s' % SERVER_PIDFILE, '--python=%s' % SERVER_PY_FILE] portal_argv = [TWISTED_BINARY, '--logfile=%s' % PORTAL_LOGFILE, - '--pidfile=%s' % PORTAL_PIDFILE, - '--python=%s' % PORTAL_PY_FILE] - + '--pidfile=%s' % PORTAL_PIDFILE, + '--python=%s' % PORTAL_PY_FILE] + # Profiling settings (read file from python shell e.g with # p = pstats.Stats('server.prof') sprof_argv = ['--savestats', @@ -242,14 +242,14 @@ def main(): '--profiler=cprofile', '--profile=portal.prof'] - # Server - + # Server + pid = get_pid(SERVER_PIDFILE) if pid and not options.noserver: print "\nEvennia Server is already running as process %(pid)s. Not restarted." % {'pid': pid} options.noserver = True if options.noserver: - server_argv = None + server_argv = None else: set_restart_mode(SERVER_RESTART, True) if options.iserver: @@ -264,19 +264,19 @@ def main(): cycle_logfile(SERVER_LOGFILE) - # Portal + # Portal pid = get_pid(PORTAL_PIDFILE) if pid and not options.noportal: - print "\nEvennia Portal is already running as process %(pid)s. Not restarted." % {'pid': pid} - options.noportal = True + print "\nEvennia Portal is already running as process %(pid)s. Not restarted." % {'pid': pid} + options.noportal = True if options.noportal: - portal_argv = None + portal_argv = None else: if options.iportal: # make portal interactive portal_argv[1] = '--nodaemon' - PORTAL_INTERACTIVE = True + PORTAL_INTERACTIVE = True set_restart_mode(PORTAL_RESTART, True) print "\nStarting Evennia Portal in non-Daemon mode (output to stdout)." else: @@ -297,7 +297,7 @@ def main(): # Start processes start_services(server_argv, portal_argv) - + if __name__ == '__main__': from src.utils.utils import check_evennia_dependencies if check_evennia_dependencies(): diff --git a/src/server/admin.py b/src/server/admin.py index f130eeac10..32194015b5 100644 --- a/src/server/admin.py +++ b/src/server/admin.py @@ -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.contrib import admin @@ -12,7 +12,7 @@ class ServerConfigAdmin(admin.ModelAdmin): list_display_links = ('db_key',) ordering = ['db_key', 'db_value'] search_fields = ['db_key'] - save_as = True - save_on_top = True - list_select_related = True + save_as = True + save_on_top = True + list_select_related = True admin.site.register(ServerConfig, ServerConfigAdmin) diff --git a/src/server/amp.py b/src/server/amp.py index b55f1c46da..1db01ccf30 100644 --- a/src/server/amp.py +++ b/src/server/amp.py @@ -4,11 +4,11 @@ to service the MUD portal proxy. The separation works like this: -Portal - (AMP client) handles protocols. It contains a list of connected sessions in a +Portal - (AMP client) handles protocols. It contains a list of connected sessions in a dictionary for identifying the respective player connected. If it looses the AMP connection - it will automatically try to reconnect. - -Server - (AMP server) Handles all mud operations. The server holds its own list + it will automatically try to reconnect. + +Server - (AMP server) Handles all mud operations. The server holds its own list of sessions tied to player objects. This is synced against the portal at startup and when a session connects/disconnects @@ -32,15 +32,15 @@ from src.server.serversession import ServerSession PORTAL_RESTART = os.path.join(settings.GAME_DIR, "portal.restart") SERVER_RESTART = os.path.join(settings.GAME_DIR, "server.restart") -# communication bits +# communication bits PCONN = chr(1) # portal session connect PDISCONN = chr(2) # portal session disconnect PSYNC = chr(3) # portal session sync SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect +SDISCONN = chr(5) # server session disconnect SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown +SSHUTD = chr(7) # server shutdown SSYNC = chr(8) # server session sync # i18n @@ -54,7 +54,7 @@ def get_restart_mode(restart_file): if os.path.exists(restart_file): flag = open(restart_file, 'r').read() return flag == "True" - return False + return False class AmpServerFactory(protocol.ServerFactory): """ @@ -66,8 +66,8 @@ class AmpServerFactory(protocol.ServerFactory): server: The Evennia server service instance protocol: The protocol the factory creates instances of. """ - self.server = server - self.protocol = AMPProtocol + self.server = server + self.protocol = AMPProtocol def buildProtocol(self, addr): """ @@ -91,7 +91,7 @@ class AmpClientFactory(protocol.ReconnectingClientFactory): maxDelay = 1 def __init__(self, portal): - self.portal = portal + self.portal = portal self.protocol = AMPProtocol def startedConnecting(self, connector): @@ -100,10 +100,10 @@ class AmpClientFactory(protocol.ReconnectingClientFactory): """ pass #print 'AMP started to connect:', connector - + def buildProtocol(self, addr): """ - Creates an AMPProtocol instance when connecting to the server. + Creates an AMPProtocol instance when connecting to the server. """ #print "Portal connected to Evennia server at %s." % addr self.resetDelay() @@ -114,7 +114,7 @@ class AmpClientFactory(protocol.ReconnectingClientFactory): def clientConnectionLost(self, connector, reason): """ Called when the AMP connection to the MUD server is lost. - """ + """ if not get_restart_mode(SERVER_RESTART): self.portal.sessions.announce_all(_(" Portal lost connection to Server.")) protocol.ReconnectingClientFactory.clientConnectionLost(self, connector, reason) @@ -128,7 +128,7 @@ class AmpClientFactory(protocol.ReconnectingClientFactory): class MsgPortal2Server(amp.Command): - """ + """ Message portal -> server """ arguments = [('sessid', amp.Integer()), @@ -138,7 +138,7 @@ class MsgPortal2Server(amp.Command): response = [] class MsgServer2Portal(amp.Command): - """ + """ Message server -> portal """ arguments = [('sessid', amp.Integer()), @@ -155,7 +155,7 @@ class OOBPortal2Server(amp.Command): ('data', amp.String())] errors = [(Exception, "EXCEPTION")] response = [] - + class OOBServer2Portal(amp.Command): """ OOB data server -> portal @@ -164,13 +164,13 @@ class OOBServer2Portal(amp.Command): ('data', amp.String())] errors = [(Exception, "EXCEPTION")] response = [] - + class ServerAdmin(amp.Command): """ Portal -> Server Sent when the portal needs to perform admin - operations on the server, such as when a new + operations on the server, such as when a new session connects or resyncs """ arguments = [('sessid', amp.Integer()), @@ -178,13 +178,13 @@ class ServerAdmin(amp.Command): ('data', amp.String())] errors = [(Exception, 'EXCEPTION')] response = [] - + class PortalAdmin(amp.Command): """ Server -> Portal Sent when the server needs to perform admin - operations on the portal. + operations on the portal. """ arguments = [('sessid', amp.Integer()), ('operation', amp.String()), @@ -209,27 +209,27 @@ class AMPProtocol(amp.AMP): subclasses that specify the datatypes of the input/output of these methods. """ - # helper methods + # helper methods def connectionMade(self): """ This is called when a connection is established between server and portal. It is called on both sides, so we need to make sure to only trigger resync from the - server side. + server side. """ if hasattr(self.factory, "portal"): sessdata = self.factory.portal.sessions.get_all_sync_data() #print sessdata - self.call_remote_ServerAdmin(0, - PSYNC, + self.call_remote_ServerAdmin(0, + PSYNC, data=sessdata) if get_restart_mode(SERVER_RESTART): msg = _(" ... Server restarted.") self.factory.portal.sessions.announce_all(msg) self.factory.portal.sessions.at_server_connection() - - # Error handling + + # Error handling def errback(self, e, info): "error handler, to avoid dropping connections on server tracebacks." @@ -240,8 +240,8 @@ class AMPProtocol(amp.AMP): # Message definition + helper methods to call/create each message type # Portal -> Server Msg - - def amp_msg_portal2server(self, sessid, msg, data): + + def amp_msg_portal2server(self, sessid, msg, data): """ Relays message to server. This method is executed on the Server. """ @@ -253,14 +253,14 @@ class AMPProtocol(amp.AMP): def call_remote_MsgPortal2Server(self, sessid, msg, data=""): """ Access method called by the Portal and executed on the Portal. - """ + """ #print "msg portal->server (portal side):", sessid, msg self.callRemote(MsgPortal2Server, sessid=sessid, msg=msg, data=dumps(data)).addErrback(self.errback, "MsgPortal2Server") - # Server -> Portal message + # Server -> Portal message def amp_msg_server2portal(self, sessid, msg, data): """ @@ -281,11 +281,11 @@ class AMPProtocol(amp.AMP): msg=to_str(msg), data=dumps(data)).addErrback(self.errback, "OOBServer2Portal") - # OOB Portal -> Server - + # OOB Portal -> Server + # Portal -> Server Msg - - def amp_oob_portal2server(self, sessid, data): + + def amp_oob_portal2server(self, sessid, data): """ Relays out-of-band data to server. This method is executed on the Server. """ @@ -297,13 +297,13 @@ class AMPProtocol(amp.AMP): def call_remote_OOBPortal2Server(self, sessid, data=""): """ Access method called by the Portal and executed on the Portal. - """ + """ #print "oob portal->server (portal side):", sessid, data self.callRemote(OOBPortal2Server, - sessid=sessid, + sessid=sessid, data=dumps(data)).addErrback(self.errback, "OOBPortal2Server") - # Server -> Portal message + # Server -> Portal message def amp_oob_server2portal(self, sessid, data): """ @@ -318,13 +318,13 @@ class AMPProtocol(amp.AMP): """ Access method called by the Server and executed on the Server. """ - #print "oob server->portal (server side):", sessid, data + #print "oob server->portal (server side):", sessid, data self.callRemote(OOBServer2Portal, - sessid=sessid, + sessid=sessid, data=dumps(data)).addErrback(self.errback, "OOBServer2Portal") - - # Server administration from the Portal side + + # Server administration from the Portal side def amp_server_admin(self, sessid, operation, data): """ This allows the portal to perform admin @@ -334,12 +334,12 @@ class AMPProtocol(amp.AMP): data = loads(data) #print "serveradmin (server side):", sessid, operation, data - + if operation == PCONN: #portal_session_connect # create a new session and sync it sess = ServerSession() sess.sessionhandler = self.factory.server.sessions - sess.load_sync_data(data) + sess.load_sync_data(data) if sess.logged_in and sess.uid: # this can happen in the case of auto-authenticating protocols like SSH sess.player = PlayerDB.objects.get_player_from_uid(sess.uid) @@ -348,24 +348,24 @@ class AMPProtocol(amp.AMP): self.factory.server.sessions.portal_connect(sessid, sess) elif operation == PDISCONN: #'portal_session_disconnect' - # session closed from portal side + # session closed from portal side self.factory.server.sessions.portal_disconnect(sessid) elif operation == PSYNC: #'portal_session_sync' - # force a resync of sessions when portal reconnects to server (e.g. after a server reboot) + # force a resync of sessions when portal reconnects to server (e.g. after a server reboot) # the data kwarg contains a dict {sessid: {arg1:val1,...}} representing the attributes # to sync for each session. sesslist = [] server_sessionhandler = self.factory.server.sessions - for sessid, sessdict in data.items(): + for sessid, sessdict in data.items(): sess = ServerSession() sess.sessionhandler = server_sessionhandler sess.load_sync_data(sessdict) if sess.uid: sess.player = PlayerDB.objects.get_player_from_uid(sess.uid) - sesslist.append(sess) + sesslist.append(sess) # replace sessions on server - server_sessionhandler.portal_session_sync(sesslist) + server_sessionhandler.portal_session_sync(sesslist) # after sync is complete we force-validate all scripts (this starts everything) init_mode = ServerConfig.objects.conf("server_restart_mode", default=None) ScriptDB.objects.validate(init_mode=init_mode) @@ -373,7 +373,7 @@ class AMPProtocol(amp.AMP): else: raise Exception(_("operation %(op)s not recognized.") % {'op': operation}) - + return {} ServerAdmin.responder(amp_server_admin) @@ -393,7 +393,7 @@ class AMPProtocol(amp.AMP): def amp_portal_admin(self, sessid, operation, data): """ - This allows the server to perform admin + This allows the server to perform admin operations on the portal. This is executed on the Portal. """ data = loads(data) @@ -401,7 +401,7 @@ class AMPProtocol(amp.AMP): #print "portaladmin (portal side):", sessid, operation, data if operation == SLOGIN: # 'server_session_login' # a session has authenticated; sync it. - sess = self.factory.portal.sessions.get_session(sessid) + sess = self.factory.portal.sessions.get_session(sessid) sess.load_sync_data(data) elif operation == SDISCONN: #'server_session_disconnect' @@ -415,14 +415,14 @@ class AMPProtocol(amp.AMP): elif operation == SSHUTD: #server_shutdown' # the server orders the portal to shut down self.factory.portal.shutdown(restart=False) - + elif operation == SSYNC: #'server_session_sync' # server wants to save session data to the portal, maybe because - # it's about to shut down. We don't overwrite any sessions, - # just update data on them and remove eventual ones that are - # out of sync (shouldn't happen normally). + # it's about to shut down. We don't overwrite any sessions, + # just update data on them and remove eventual ones that are + # out of sync (shouldn't happen normally). - portal_sessionhandler = self.factory.portal.sessions.sessions + portal_sessionhandler = self.factory.portal.sessions.sessions to_save = [sessid for sessid in data if sessid in portal_sessionhandler.sessions] to_delete = [sessid for sessid in data if sessid not in to_save] @@ -449,10 +449,3 @@ class AMPProtocol(amp.AMP): sessid=sessid, operation=operation, data=data).addErrback(self.errback, "PortalAdmin") - - - - - - - diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index 458acebf82..e44146945c 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -11,7 +11,7 @@ from django.core import management from django.conf import settings from src.server.models import ServerConfig from src.help.models import HelpEntry -from src.utils import create +from src.utils import create # i18n from django.utils.translation import ugettext as _ @@ -19,7 +19,7 @@ from django.utils.translation import ugettext as _ def create_config_values(): """ Creates the initial config values. - """ + """ ServerConfig.objects.conf("site_name", settings.SERVERNAME) ServerConfig.objects.conf("idle_timeout", settings.IDLE_TIMEOUT) @@ -33,28 +33,28 @@ def create_objects(): """ Creates the #1 player and Limbo room. """ - + print _(" Creating objects (Player #1 and Limbo room) ...") # Set the initial User's account object's username on the #1 object. - # This object is pure django and only holds name, email and password. + # This object is pure django and only holds name, email and password. god_user = get_god_user() # Create a Player 'user profile' object to hold eventual # mud-specific settings for the bog standard User object. This is # accessed by user.get_profile() and can also store attributes. # It also holds mud permissions, but for a superuser these - # have no effect anyhow. + # have no effect anyhow. character_typeclass = settings.BASE_CHARACTER_TYPECLASS # Create the Player object as well as the in-game god-character # for user #1. We can't set location and home yet since nothing # exists. Also, all properties (name, email, password, is_superuser) - # is inherited from the user so we don't specify it again here. + # is inherited from the user so we don't specify it again here. - god_character = create.create_player(god_user.username, None, None, - user=god_user, + god_character = create.create_player(god_user.username, None, None, + user=god_user, create_character=True, character_typeclass=character_typeclass) @@ -66,7 +66,7 @@ def create_objects(): god_character.locks.add("examine:perm(Immortals);edit:false();delete:false();boot:false();msg:all();puppet:false()") god_character.save() - + # Limbo is the default "nowhere" starting room room_typeclass = settings.BASE_ROOM_TYPECLASS @@ -83,11 +83,11 @@ def create_objects(): # Now that Limbo exists, try to set the user up in Limbo (unless # the creation hooks already fixed this). - if not god_character.location: + if not god_character.location: god_character.location = limbo_obj if not god_character.home: god_character.home = limbo_obj - + def create_channels(): """ Creates some sensible default channels. @@ -97,7 +97,7 @@ def create_channels(): # public channel key, aliases, desc, locks = settings.CHANNEL_PUBLIC pchan = create.create_channel(key, aliases, desc, locks=locks) - # mudinfo channel + # mudinfo channel key, aliases, desc, locks = settings.CHANNEL_MUDINFO ichan = create.create_channel(key, aliases, desc, locks=locks) # connectinfo channel @@ -110,29 +110,29 @@ def create_channels(): PlayerChannelConnection.objects.create_connection(goduser, pchan) PlayerChannelConnection.objects.create_connection(goduser, ichan) PlayerChannelConnection.objects.create_connection(goduser, cchan) - + def import_MUX_help_files(): """ Imports the MUX help files. - """ + """ print _(" Importing MUX help database (devel reference only) ...") - management.call_command('loaddata', '../src/help/mux_help_db.json', verbosity=0) + management.call_command('loaddata', '../src/help/mux_help_db.json', verbosity=0) # categorize the MUX help files into its own category. default_category = "MUX" print _(" Moving imported help db to help category '%(default)s'." \ % {'default': default_category}) HelpEntry.objects.all_to_category(default_category) - + def create_system_scripts(): """ Setup the system repeat scripts. They are automatically started - by the create_script function. + by the create_script function. """ from src.scripts import scripts print _(" Creating and starting global scripts ...") - # check so that all sessions are alive. + # check so that all sessions are alive. script1 = create.create_script(scripts.CheckSessions) # validate all scripts in script table. script2 = create.create_script(scripts.ValidateScripts) @@ -140,7 +140,7 @@ def create_system_scripts(): script3 = create.create_script(scripts.ValidateChannelHandler) if not script1 or not script2 or not script3: print _(" Error creating system scripts.") - + def start_game_time(): """ This starts a persistent script that keeps track of the @@ -155,7 +155,7 @@ def start_game_time(): def create_admin_media_links(): """ This traverses to src/web/media and tries to create a symbolic - link to the django media files from within the MEDIA_ROOT. + link to the django media files from within the MEDIA_ROOT. These are files we normally don't want to mess with (use templates to customize the admin look). Linking is needed since the Twisted webserver otherwise has no @@ -168,8 +168,8 @@ def create_admin_media_links(): apath = os.path.join(settings.ADMIN_MEDIA_ROOT) if os.path.isdir(apath): print _(" ADMIN_MEDIA_ROOT already exists. Ignored.") - return - if os.name == 'nt': + return + if os.name == 'nt': print _(" Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode).") os.mkdir(apath) os.system('xcopy "%s" "%s" /e /q /c' % (dpath, apath)) @@ -188,34 +188,34 @@ def at_initial_setup(): """ modname = settings.AT_INITIAL_SETUP_HOOK_MODULE if not modname: - return - try: + return + try: mod = __import__(modname, fromlist=[None]) except ImportError, ValueError: - return + return print _(" Running at_initial_setup() hook.") if mod.__dict__.get("at_initial_setup", None): - mod.at_initial_setup() - + mod.at_initial_setup() + def handle_setup(last_step): """ Main logic for the module. It allows for restarting - the initialization at any point if one of the modules - should crash. + the initialization at any point if one of the modules + should crash. """ if last_step < 0: # this means we don't need to handle setup since - # it already ran sucessfully once. + # it already ran sucessfully once. return elif last_step == None: # config doesn't exist yet. First start of server last_step = 0 - - # setting up the list of functions to run + + # setting up the list of functions to run setup_queue = [ - create_config_values, - create_objects, + create_config_values, + create_objects, create_channels, create_system_scripts, start_game_time, @@ -224,17 +224,17 @@ def handle_setup(last_step): at_initial_setup] if not settings.IMPORT_MUX_HELP: - # skip importing of the MUX helpfiles, they are + # skip importing of the MUX helpfiles, they are # not interesting except for developers. del setup_queue[-2] - #print " Initial setup: %s steps." % (len(setup_queue)) + #print " Initial setup: %s steps." % (len(setup_queue)) # step through queue, from last completed function - for num, setup_func in enumerate(setup_queue[last_step:]): + for num, setup_func in enumerate(setup_queue[last_step:]): # run the setup function. Note that if there is a # traceback we let it stop the system so the config - # step is not saved. + # step is not saved. #print "%s..." % num try: @@ -255,10 +255,10 @@ def handle_setup(last_step): chan.delete() for conn in PlayerChannelConnection.objects.all(): conn.delete() - - raise - ServerConfig.objects.conf("last_initial_setup_step", last_step + num + 1) + + raise + ServerConfig.objects.conf("last_initial_setup_step", last_step + num + 1) # We got through the entire list. Set last_step to -1 so we don't # have to run this again. - ServerConfig.objects.conf("last_initial_setup_step", -1) + ServerConfig.objects.conf("last_initial_setup_step", -1) diff --git a/src/server/manager.py b/src/server/manager.py index 88c196c10a..c0a2d866e5 100644 --- a/src/server/manager.py +++ b/src/server/manager.py @@ -5,17 +5,17 @@ from django.db import models class ServerConfigManager(models.Manager): """ - This ServerConfigManager implements methods for searching + This ServerConfigManager implements methods for searching and manipulating ServerConfigs directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - ServerConfigs are used to store certain persistent settings for the + ServerConfigs are used to store certain persistent settings for the server at run-time. Evennia-specific: - conf + conf """ def conf(self, key=None, value=None, delete=False, default=None): @@ -27,13 +27,13 @@ class ServerConfigManager(models.Manager): elif delete == True: for conf in self.filter(db_key=key): conf.delete() - elif value != None: + elif value != None: conf = self.filter(db_key=key) if conf: conf = conf[0] else: - conf = self.model(db_key=key) - conf.value = value # this will pickle + conf = self.model(db_key=key) + conf.value = value # this will pickle else: conf = self.filter(db_key=key) if not conf: diff --git a/src/server/mccp.py b/src/server/mccp.py index 7e583945b8..9cf7b34d5d 100644 --- a/src/server/mccp.py +++ b/src/server/mccp.py @@ -12,52 +12,52 @@ effect of MCCP unless you have extremely heavy traffic or sits on a terribly slow connection. This protocol is implemented by the telnet protocol importing -mccp_compress and calling it from its write methods. +mccp_compress and calling it from its write methods. """ -import zlib +import zlib # negotiations for v1 and v2 of the protocol MCCP = chr(86) FLUSH = zlib.Z_SYNC_FLUSH def mccp_compress(protocol, data): - "Handles zlib compression, if applicable" + "Handles zlib compression, if applicable" if hasattr(protocol, 'zlib'): return protocol.zlib.compress(data) + protocol.zlib.flush(FLUSH) - return data + return data class Mccp(object): """ - Implements the MCCP protocol. Add this to a + Implements the MCCP protocol. Add this to a variable on the telnet protocol to set it up. """ def __init__(self, protocol): """ - initialize MCCP by storing protocol on - ourselves and calling the client to see if - it supports MCCP. Sets callbacks to - start zlib compression in that case. + initialize MCCP by storing protocol on + ourselves and calling the client to see if + it supports MCCP. Sets callbacks to + start zlib compression in that case. """ - + self.protocol = protocol - self.protocol.protocol_flags['MCCP'] = False + self.protocol.protocol_flags['MCCP'] = False # ask if client will mccp, connect callbacks to handle answer self.protocol.will(MCCP).addCallbacks(self.do_mccp, self.no_mccp) def no_mccp(self, option): """ If client doesn't support mccp, don't do anything. - """ + """ if hasattr(self.protocol, 'zlib'): del self.protocol.zlib - self.protocol.protocol_flags['MCCP'] = False + self.protocol.protocol_flags['MCCP'] = False def do_mccp(self, option): """ - The client supports MCCP. Set things up by - creating a zlib compression stream. - """ - self.protocol.protocol_flags['MCCP'] = True + The client supports MCCP. Set things up by + creating a zlib compression stream. + """ + self.protocol.protocol_flags['MCCP'] = True self.protocol.requestNegotiation(MCCP, '') self.protocol.zlib = zlib.compressobj(9) diff --git a/src/server/models.py b/src/server/models.py index a6aabd3f7e..995439ff2f 100644 --- a/src/server/models.py +++ b/src/server/models.py @@ -4,8 +4,8 @@ Server Configuration flags This holds persistent server configuration flags. -Config values should usually be set through the -manager's conf() method. +Config values should usually be set through the +manager's conf() method. """ try: @@ -26,10 +26,10 @@ from django.utils.translation import ugettext as _ # ServerConfig # #------------------------------------------------------------ - + class ServerConfig(SharedMemoryModel): """ - On-the fly storage of global settings. + On-the fly storage of global settings. Properties defined on ServerConfig: key - main identifier @@ -50,15 +50,15 @@ class ServerConfig(SharedMemoryModel): db_value = models.TextField(blank=True) objects = ServerConfigManager() - + # 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). - + # key property (wraps db_key) #@property def key_get(self): @@ -86,12 +86,12 @@ class ServerConfig(SharedMemoryModel): if utils.has_parent('django.db.models.base.Model', value): # we have to protect against storing db objects. logger.log_errmsg(_("ServerConfig cannot store db objects! (%s)" % value)) - return + return self.db_value = pickle.dumps(value) self.save() #@value.deleter def value_del(self): - "Deleter. Allows for del self.value. Deletes entry." + "Deleter. Allows for del self.value. Deletes entry." self.delete() value = property(value_get, value_set, value_del) @@ -100,8 +100,8 @@ class ServerConfig(SharedMemoryModel): verbose_name = "Server Config value" verbose_name_plural = "Server Config values" - # - # ServerConfig other methods + # + # ServerConfig other methods # def __unicode__(self): diff --git a/src/server/msdp.py b/src/server/msdp.py index 3cf36ded2d..aac6ca4fb0 100644 --- a/src/server/msdp.py +++ b/src/server/msdp.py @@ -28,14 +28,14 @@ regex_varval = re.compile(r"%s(.*?)%s(.*?)[%s]" % (MSDP_VAR, MSDP_VAL, ENDING)) class Msdp(object): """ - Implements the MSDP protocol. + Implements the MSDP protocol. """ - + def __init__(self, protocol): """ Initiates by storing the protocol on itself and trying to determine - if the client supports MSDP. + if the client supports MSDP. """ self.protocol = protocol self.protocol.protocol_FLAGS['MSDP'] = False @@ -45,39 +45,39 @@ class Msdp(object): def no_msdp(self, option): "No msdp" pass - + def do_msdp(self, option): """ - Called when client confirms that it can do MSDP. + Called when client confirms that it can do MSDP. """ - self.protocol.protocol_flags['MSDP'] = True - + self.protocol.protocol_flags['MSDP'] = True + def func_to_msdp(self, cmdname, data): """ - handle return data from cmdname by converting it to - a proper msdp structure. data can either be a single value (will be - converted to a string), a list (will be converted to an MSDP_ARRAY), - or a dictionary (will be converted to MSDP_TABLE). + handle return data from cmdname by converting it to + a proper msdp structure. data can either be a single value (will be + converted to a string), a list (will be converted to an MSDP_ARRAY), + or a dictionary (will be converted to MSDP_TABLE). - OBS - this supports nested tables and even arrays nested - inside tables, as opposed to the receive method. Arrays + OBS - this supports nested tables and even arrays nested + inside tables, as opposed to the receive method. Arrays cannot hold tables by definition (the table must be named - with MSDP_VAR, and an array can only contain MSDP_VALs). + with MSDP_VAR, and an array can only contain MSDP_VALs). """ - - def make_table(name, datadict, string): + + def make_table(name, datadict, string): "build a table that may be nested with other tables or arrays." string += MSDP_VAR + name + MSDP_VAL + MSDP_TABLE_OPEN - for key, val in datadict.items(): + for key, val in datadict.items(): if type(val) == type({}): string += make_table(key, val, string) - elif hasattr(val, '__iter__'): - string += make_array(key, val, string) + elif hasattr(val, '__iter__'): + string += make_array(key, val, string) else: string += MSDP_VAR + key + MSDP_VAL + val - string += MSDP_TABLE_CLOSE - return string + string += MSDP_TABLE_CLOSE + return string def make_array(name, string, datalist): "build a simple array. Arrays may not nest tables by definition." @@ -85,23 +85,23 @@ class Msdp(object): for val in datalist: string += MSDP_VAL + val string += MSDP_ARRAY_CLOSE - return string + return string - if type(data) == type({}): + if type(data) == type({}): msdp_string = make_table(cmdname, data, "") elif hasattr(data, '__iter__'): msdp_string = make_array(cmdname, data, "") else: msdp_string = MSDP_VAR + cmdname + MSDP_VAL + data - return msdp_string + return msdp_string def msdp_to_func(self, data): """ Handle a client's requested negotiation, converting it into a function mapping - OBS-this does not support receiving nested tables - from the client at this point! + OBS-this does not support receiving nested tables + from the client at this point! """ tables = {} arrays = {} @@ -112,23 +112,23 @@ class Msdp(object): for array in regex_array.findall(data): arrays[array[0]] = dict(regex_varval(array[1])) variables = dict(regex._varval(regex_array.sub("", regex_table.sub("", data)))) - - # MSDP Commands - # Some given MSDP (varname, value) pairs can also be treated as command + argument. + + # MSDP Commands + # Some given MSDP (varname, value) pairs can also be treated as command + argument. # Generic msdp command map. The argument will be sent to the given command. - # See http://tintin.sourceforge.net/msdp/ for definitions of each command. - # These are client->server commands. + # See http://tintin.sourceforge.net/msdp/ for definitions of each command. + # These are client->server commands. def msdp_cmd_list(self, arg): """ The List command allows for retrieving various info about the server/client - """ + """ if arg == 'COMMANDS': return self.func_to_msdp(arg, MSDP_COMMANDS.keys()) elif arg == 'LISTS': - return self.func_to_msdp(arg, ("COMMANDS", "LISTS", - "CONFIGURABLE_VARIABLES", + return self.func_to_msdp(arg, ("COMMANDS", "LISTS", + "CONFIGURABLE_VARIABLES", "REPORTED_VARIABLES", "SENDABLE_VARIABLES")) elif arg == 'CONFIGURABLE_VARIABLES': return self.func_to_msdp(arg, ("CLIENT_NAME", "CLIENT_VERSION", "PLUGIN_ID")) @@ -149,7 +149,7 @@ class Msdp(object): try: MSDP_REPORTABLE[arg](report=True) except Exception: - logger.log_trace() + logger.log_trace() def msdp_cmd_unreport(self, arg): """ @@ -159,7 +159,7 @@ class Msdp(object): MSDP_REPORTABLE[arg](eport=False) except Exception: logger.log_trace() - + def msdp_cmd_reset(self, arg): """ The reset command resets a variable to its initial state. @@ -167,12 +167,12 @@ class Msdp(object): try: MSDP_REPORTABLE[arg](reset=True) except Exception: - logger.log_trace() + logger.log_trace() def msdp_cmd_send(self, arg): """ Request the server to send a particular variable - to the client. + to the client. arg - this is a list of variables the client wants. """ @@ -181,8 +181,8 @@ class Msdp(object): try: ret.append(MSDP_REPORTABLE[arg](send=True)) except Exception: - logger.log_trace() - return ret + logger.log_trace() + return ret MSDP_COMMANDS = { "LIST": self.msdp_list, @@ -192,57 +192,57 @@ class Msdp(object): "UNREPORT":"mspd_unreport" } - # MSDP_MAP is a standard suggestions for making it easy to create generic guis. + # MSDP_MAP is a standard suggestions for making it easy to create generic guis. # this maps MSDP command names to Evennia commands found in OOB_FUNC_MODULE. It - # is up to these commands to return data on proper form. + # is up to these commands to return data on proper form. MSDP_REPORTABLE = { # General "CHARACTER_NAME": "get_character_name", "SERVER_ID": "get_server_id", "SERVER_TIME": "get_server_time", - - # Character + + # Character "AFFECTS": "char_affects", "ALIGNMENT": "char_alignment", "EXPERIENCE": "char_experience", "EXPERIENCE_MAX": "char_experience_max", "EXPERIENCE_TNL": "char_experience_tnl", - "HEALTH": "char_health", - "HEALTH_MAX": "char_health_max", - "LEVEL": "char_level", + "HEALTH": "char_health", + "HEALTH_MAX": "char_health_max", + "LEVEL": "char_level", "RACE": "char_race", - "CLASS": "char_class", - "MANA": "char_mana", + "CLASS": "char_class", + "MANA": "char_mana", "MANA_MAX": "char_mana_max", - "WIMPY": "char_wimpy", - "PRACTICE": "char_practice", - "MONEY": "char_money", + "WIMPY": "char_wimpy", + "PRACTICE": "char_practice", + "MONEY": "char_money", "MOVEMENT": "char_movement", "MOVEMENT_MAX": "char_movement_max", - "HITROLL": "char_hitroll", - "DAMROLL": "char_damroll", + "HITROLL": "char_hitroll", + "DAMROLL": "char_damroll", "AC": "char_ac", - "STR": "char_str", - "INT": "char_int", + "STR": "char_str", + "INT": "char_int", "WIS": "char_wis", - "DEX": "char_dex", - "CON": "char_con", - - # Combat + "DEX": "char_dex", + "CON": "char_con", + + # Combat "OPPONENT_HEALTH": "opponent_health", "OPPONENT_HEALTH_MAX":"opponent_health_max", "OPPONENT_LEVEL": "opponent_level", "OPPONENT_NAME": "opponent_name", - # World + # World "AREA_NAME": "area_name", "ROOM_EXITS": "area_room_exits", - "ROOM_NAME": "room_name", - "ROOM_VNUM": "room_dbref", + "ROOM_NAME": "room_name", + "ROOM_VNUM": "room_dbref", "WORLD_TIME": "world_time", - - # Configurable variables - "CLIENT_ID": "client_id", + + # Configurable variables + "CLIENT_ID": "client_id", "CLIENT_VERSION": "client_version", "PLUGIN_ID": "plugin_id", "ANSI_COLORS": "ansi_colours", @@ -250,13 +250,13 @@ class Msdp(object): "UTF_8": "utf_8", "SOUND": "sound", "MXP": "mxp", - - # GUI variables + + # GUI variables "BUTTON_1": "button1", "BUTTON_2": "button2", "BUTTON_3": "button3", "BUTTON_4": "button4", - "BUTTON_5": "button5", + "BUTTON_5": "button5", "GAUGE_1": "gauge1", "GAUGE_2": "gauge2", "GAUGE_3": "gauge3", diff --git a/src/server/mssp.py b/src/server/mssp.py index 6b9d2ac7fe..c62975945d 100644 --- a/src/server/mssp.py +++ b/src/server/mssp.py @@ -4,9 +4,9 @@ MSSP - Mud Server Status Protocol This implements the MSSP telnet protocol as per http://tintin.sourceforge.net/mssp/. MSSP allows web portals and -listings to have their crawlers find the mud and automatically -extract relevant information about it, such as genre, how many -active players and so on. +listings to have their crawlers find the mud and automatically +extract relevant information about it, such as genre, how many +active players and so on. Most of these settings are de @@ -19,23 +19,23 @@ MSSP_VAR = chr(1) MSSP_VAL = chr(2) -# try to get the customized mssp info, if it exists. -MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={}) +# try to get the customized mssp info, if it exists. +MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={}) class Mssp(object): """ - Implements the MSSP protocol. Add this to a - variable on the telnet protocol to set it up. + Implements the MSSP protocol. Add this to a + variable on the telnet protocol to set it up. """ def __init__(self, protocol): """ initialize MSSP by storing protocol on ourselves and calling the client to see if it supports - MSSP. + MSSP. """ self.protocol = protocol self.protocol.will(MSSP).addCallbacks(self.do_mssp, self.no_mssp) - + def get_player_count(self): "Get number of logged-in players" return str(self.protocol.sessionhandler.count_loggedin()) @@ -52,31 +52,31 @@ class Mssp(object): def do_mssp(self, option): """ - Negotiate all the information. + Negotiate all the information. """ self.mssp_table = { - # Required fields + # Required fields "NAME": "Evennia", - "PLAYERS": self.get_player_count, - "UPTIME" : self.get_uptime, + "PLAYERS": self.get_player_count, + "UPTIME" : self.get_uptime, # Generic "CRAWL DELAY": "-1", - "HOSTNAME": "", # current or new hostname + "HOSTNAME": "", # current or new hostname "PORT": ["4000"], # most important port should be last in list "CODEBASE": "Evennia", "CONTACT": "", # email for contacting the mud "CREATED": "", # year MUD was created - "ICON": "", # url to icon 32x32 or larger; <32kb. + "ICON": "", # url to icon 32x32 or larger; <32kb. "IP": "", # current or new IP address "LANGUAGE": "", # name of language used, e.g. English "LOCATION": "", # full English name of server country - "MINIMUM AGE": "0", # set to 0 if not applicable + "MINIMUM AGE": "0", # set to 0 if not applicable "WEBSITE": "www.evennia.com", # Categorisation @@ -88,14 +88,14 @@ class Mssp(object): # Roleplaying, Simulation, Social or Strategy "STATUS": "Open Beta", # Alpha, Closed Beta, Open Beta, Live "GAMESYSTEM": "Custom", # D&D, d20 System, World of Darkness, etc. Use Custom if homebrew - "INTERMUD": "IMC2", # evennia supports IMC2. - "SUBGENRE": "None", # LASG, Medieval Fantasy, World War II, Frankenstein, + "INTERMUD": "IMC2", # evennia supports IMC2. + "SUBGENRE": "None", # LASG, Medieval Fantasy, World War II, Frankenstein, # Cyberpunk, Dragonlance, etc. Or None if not available. # World - "AREAS": "0", - "HELPFILES": "0", + "AREAS": "0", + "HELPFILES": "0", "MOBILES": "0", "OBJECTS": "0", "ROOMS": "0", # use 0 if room-less @@ -128,7 +128,7 @@ class Mssp(object): "HIRING BUILDERS": "0", "HIRING CODERS": "0", - # Extended variables + # Extended variables # World diff --git a/src/server/portal.py b/src/server/portal.py index 0ecdb76457..73b1a16f7a 100644 --- a/src/server/portal.py +++ b/src/server/portal.py @@ -1,6 +1,6 @@ """ This module implements the main Evennia server process, the core of -the game engine. +the game engine. This module should be started with the 'twistd' executable since it sets up all the networking features. (this is done automatically @@ -30,7 +30,7 @@ if os.name == 'nt': from django.utils.translation import ugettext as _ #------------------------------------------------------------ -# Evennia Portal settings +# Evennia Portal settings #------------------------------------------------------------ VERSION = get_evennia_version() @@ -53,15 +53,15 @@ TELNET_ENABLED = settings.TELNET_ENABLED and TELNET_PORTS and TELNET_INTERFACES SSL_ENABLED = settings.SSL_ENABLED and SSL_PORTS and SSL_INTERFACES SSH_ENABLED = settings.SSH_ENABLED and SSH_PORTS and SSH_INTERFACES WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES -WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED +WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED AMP_HOST = settings.AMP_HOST AMP_PORT = settings.AMP_PORT -AMP_ENABLED = AMP_HOST and AMP_PORT +AMP_ENABLED = AMP_HOST and AMP_PORT #------------------------------------------------------------ -# Portal Service object +# Portal Service object #------------------------------------------------------------ class Portal(object): @@ -69,17 +69,17 @@ class Portal(object): The main Portal server handler. This object sets up the database and tracks and interlinks all the twisted network services that make up Portal. - """ - + """ + def __init__(self, application): """ - Setup the server. + Setup the server. application - an instantiated Twisted application - """ + """ sys.path.append('.') - + # create a store of services self.services = service.IServiceCollection(application) self.amp_protocol = None # set by amp factory @@ -88,25 +88,25 @@ class Portal(object): print '\n' + '-'*50 - # Make info output to the terminal. + # Make info output to the terminal. self.terminal_output() - print '-'*50 + print '-'*50 - # set a callback if the server is killed abruptly, + # set a callback if the server is killed abruptly, # by Ctrl-C, reboot etc. reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, _abrupt=True) self.game_running = False - + def terminal_output(self): """ Outputs server startup info to the terminal. """ - print _(' %(servername)s Portal (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} + print _(' %(servername)s Portal (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} if AMP_ENABLED: print " amp (Server): %s" % AMP_PORT - if TELNET_ENABLED: + if TELNET_ENABLED: ports = ", ".join([str(port) for port in TELNET_PORTS]) ifaces = ",".join([" %s" % iface for iface in TELNET_INTERFACES if iface != '0.0.0.0']) print " telnet%s: %s" % (ifaces, ports) @@ -129,11 +129,11 @@ class Portal(object): def set_restart_mode(self, mode=None): """ This manages the flag file that tells the runner if the server should - be restarted or is shutting down. Valid modes are True/False and None. + be restarted or is shutting down. Valid modes are True/False and None. If mode is None, no change will be done to the flag file. """ if mode == None: - return + return f = open(PORTAL_RESTART, 'w') print _("writing mode=%(mode)s to %(portal_restart)s") % {'mode': mode, 'portal_restart': PORTAL_RESTART} f.write(str(mode)) @@ -141,13 +141,13 @@ class Portal(object): def shutdown(self, restart=None, _abrupt=False): """ - Shuts down the server from inside it. + Shuts down the server from inside it. restart - True/False sets the flags so the server will be restarted or not. If None, the current flag setting (set at initialization or previous runs) is used. _abrupt - this is set if server is stopped by a kill command, - in which case the reactor is dead anyway. + in which case the reactor is dead anyway. Note that restarting (regardless of the setting) will not work if the Portal is currently running in daemon mode. In that @@ -157,7 +157,7 @@ class Portal(object): if not _abrupt: reactor.callLater(0, reactor.stop) if os.name == 'nt' and os.path.exists(PORTAL_PIDFILE): - # for Windows we need to remove pid files manually + # for Windows we need to remove pid files manually os.remove(PORTAL_PIDFILE) #------------------------------------------------------------ @@ -170,15 +170,15 @@ class Portal(object): # what to execute from. application = service.Application('Portal') -# The main Portal server program. This sets up the database +# The main Portal server program. This sets up the database # and is where we store all the other services. PORTAL = Portal(application) -if AMP_ENABLED: +if AMP_ENABLED: # The AMP protocol handles the communication between # the portal and the mud server. Only reason to ever deactivate - # it would be during testing and debugging. + # it would be during testing and debugging. from src.server import amp @@ -188,7 +188,7 @@ if AMP_ENABLED: PORTAL.services.addService(amp_client) # We group all the various services under the same twisted app. -# These will gradually be started as they are initialized below. +# These will gradually be started as they are initialized below. if TELNET_ENABLED: @@ -200,7 +200,7 @@ if TELNET_ENABLED: ifacestr = "" if interface != '0.0.0.0' or len(TELNET_INTERFACES) > 1: ifacestr = "-%s" % interface - for port in TELNET_PORTS: + for port in TELNET_PORTS: pstring = "%s:%s" % (ifacestr, port) factory = protocol.ServerFactory() factory.protocol = telnet.TelnetProtocol @@ -219,7 +219,7 @@ if SSL_ENABLED: ifacestr = "" if interface != '0.0.0.0' or len(SSL_INTERFACES) > 1: ifacestr = "-%s" % interface - for port in SSL_PORTS: + for port in SSL_PORTS: pstring = "%s:%s" % (ifacestr, port) factory = protocol.ServerFactory() factory.sessionhandler = PORTAL_SESSIONS @@ -231,7 +231,7 @@ if SSL_ENABLED: if SSH_ENABLED: # Start SSH game connections. Will create a keypair in evennia/game if necessary. - + from src.server import ssh for interface in SSH_INTERFACES: @@ -242,7 +242,7 @@ if SSH_ENABLED: pstring = "%s:%s" % (ifacestr, port) factory = ssh.makeFactory({'protocolFactory':ssh.SshProtocol, 'protocolArgs':(), - 'sessions':PORTAL_SESSIONS}) + 'sessions':PORTAL_SESSIONS}) ssh_service = internet.TCPServer(port, factory, interface=interface) ssh_service.setName('EvenniaSSH%s' % pstring) PORTAL.services.addService(ssh_service) @@ -254,14 +254,14 @@ if WEBSERVER_ENABLED: from twisted.python import threadpool from src.server.webserver import DjangoWebRoot, WSGIWebServer - # start a thread pool and define the root url (/) as a wsgi resource + # start a thread pool and define the root url (/) as a wsgi resource # recognized by Django threads = threadpool.ThreadPool() web_root = DjangoWebRoot(threads) - # point our media resources to url /media - web_root.putChild("media", static.File(settings.MEDIA_ROOT)) + # point our media resources to url /media + web_root.putChild("media", static.File(settings.MEDIA_ROOT)) - if WEBCLIENT_ENABLED: + if WEBCLIENT_ENABLED: # create ajax client processes at /webclientdata from src.server.webclient import WebClient webclient = WebClient() diff --git a/src/server/server.py b/src/server/server.py index 9b66703b62..8f4526f73f 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -1,6 +1,6 @@ """ This module implements the main Evennia server process, the core of -the game engine. +the game engine. This module should be started with the 'twistd' executable since it sets up all the networking features. (this is done automatically @@ -19,7 +19,7 @@ if os.name == 'nt': from twisted.application import internet, service from twisted.internet import protocol, reactor, defer from twisted.web import server, static -import django +import django from django.db import connection from django.conf import settings @@ -38,20 +38,20 @@ if os.name == 'nt': # a file with a flag telling the server to restart after shutdown or not. SERVER_RESTART = os.path.join(settings.GAME_DIR, 'server.restart') -# module containing hook methods +# module containing hook methods SERVER_HOOK_MODULE = mod_import(settings.AT_SERVER_STARTSTOP_MODULE) # i18n from django.utils.translation import ugettext as _ #------------------------------------------------------------ -# Evennia Server settings +# Evennia Server settings #------------------------------------------------------------ SERVERNAME = settings.SERVERNAME VERSION = get_evennia_version() -AMP_ENABLED = True +AMP_ENABLED = True AMP_HOST = settings.AMP_HOST AMP_PORT = settings.AMP_PORT @@ -61,7 +61,7 @@ IRC_ENABLED = settings.IRC_ENABLED RSS_ENABLED = settings.RSS_ENABLED #------------------------------------------------------------ -# Evennia Main Server object +# Evennia Main Server object #------------------------------------------------------------ class Evennia(object): @@ -69,15 +69,15 @@ class Evennia(object): The main Evennia server handler. This object sets up the database and tracks and interlinks all the twisted network services that make up evennia. - """ - + """ + def __init__(self, application): """ - Setup the server. + Setup the server. application - an instantiated Twisted application - """ + """ sys.path.append('.') # create a store of services @@ -85,44 +85,44 @@ class Evennia(object): self.amp_protocol = None # set by amp factory self.sessions = SESSIONS self.sessions.server = self - + print '\n' + '-'*50 # Database-specific startup optimizations. self.sqlite3_prep() - - # Run the initial setup if needed + + # Run the initial setup if needed self.run_initial_setup() self.start_time = time.time() # initialize channelhandler channelhandler.CHANNELHANDLER.update() - - # Make info output to the terminal. + + # Make info output to the terminal. self.terminal_output() - print '-'*50 + print '-'*50 - # set a callback if the server is killed abruptly, + # set a callback if the server is killed abruptly, # by Ctrl-C, reboot etc. reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, _abrupt=True) self.game_running = True self.run_init_hooks() - + # Server startup methods def sqlite3_prep(self): """ Optimize some SQLite stuff at startup since we can't save it to the database. - """ + """ if ((".".join(str(i) for i in django.VERSION) < "1.2" and settings.DATABASE_ENGINE == "sqlite3") - or (hasattr(settings, 'DATABASES') - and settings.DATABASES.get("default", {}).get('ENGINE', None) - == 'django.db.backends.sqlite3')): + or (hasattr(settings, 'DATABASES') + and settings.DATABASES.get("default", {}).get('ENGINE', None) + == 'django.db.backends.sqlite3')): cursor = connection.cursor() cursor.execute("PRAGMA cache_size=10000") cursor.execute("PRAGMA synchronous=OFF") @@ -147,7 +147,7 @@ class Evennia(object): # the last failed module. When all are finished, the step # is set to -1 to show it does not need to be run again. print _(' Resuming initial setup from step %(last)s.' % \ - {'last': last_initial_setup_step}) + {'last': last_initial_setup_step}) initial_setup.handle_setup(int(last_initial_setup_step)) print '-'*50 @@ -164,25 +164,25 @@ class Evennia(object): # call server hook. if SERVER_HOOK_MODULE: - SERVER_HOOK_MODULE.at_server_start() + SERVER_HOOK_MODULE.at_server_start() def terminal_output(self): """ Outputs server startup info to the terminal. """ - print _(' %(servername)s Server (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} + print _(' %(servername)s Server (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} print ' amp (Portal): %s' % AMP_PORT def set_restart_mode(self, mode=None): """ This manages the flag file that tells the runner if the server is - reloading, resetting or shutting down. Valid modes are - 'reload', 'reset', 'shutdown' and None. + reloading, resetting or shutting down. Valid modes are + 'reload', 'reset', 'shutdown' and None. If mode is None, no change will be done to the flag file. - Either way, the active restart setting (Restart=True/False) is + Either way, the active restart setting (Restart=True/False) is returned so the server knows which more it's in. - """ + """ if mode == None: if os.path.exists(SERVER_RESTART) and 'True' == open(SERVER_RESTART, 'r').read(): mode = 'reload' @@ -197,17 +197,17 @@ class Evennia(object): def shutdown(self, mode=None, _abrupt=False): """ - Shuts down the server from inside it. + Shuts down the server from inside it. - mode - sets the server restart mode. + 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. + None - keep currently set flag from flag file. _abrupt - this is set if server is stopped by a kill command, - in which case the reactor is dead anyway. + in which case the reactor is dead anyway. """ - mode = self.set_restart_mode(mode) + mode = self.set_restart_mode(mode) # call shutdown hooks on all cached objects @@ -217,7 +217,7 @@ class Evennia(object): if mode == 'reload': # call restart hooks - [(o.typeclass, o.at_server_reload()) for o in ObjectDB.get_all_cached_instances()] + [(o.typeclass, o.at_server_reload()) for o in ObjectDB.get_all_cached_instances()] [(p.typeclass, p.at_server_reload()) for p in PlayerDB.get_all_cached_instances()] [(s.typeclass, s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()] @@ -226,23 +226,23 @@ class Evennia(object): else: if mode == 'reset': # don't call disconnect hooks on reset - [(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] + [(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] else: # shutdown - [(o.typeclass, o.at_disconnect(), o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] + [(o.typeclass, o.at_disconnect(), o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] [(p.typeclass, p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()] - [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()] - + [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()] + ServerConfig.objects.conf("server_restart_mode", "reset") - + if not _abrupt: if SERVER_HOOK_MODULE: SERVER_HOOK_MODULE.at_server_stop() reactor.callLater(0, reactor.stop) if os.name == 'nt' and os.path.exists(SERVER_PIDFILE): - # for Windows we need to remove pid files manually + # for Windows we need to remove pid files manually os.remove(SERVER_PIDFILE) - + #------------------------------------------------------------ # # Start the Evennia game server and add all active services @@ -250,21 +250,21 @@ class Evennia(object): #------------------------------------------------------------ # Tell the system the server is starting up; some things are not available yet -ServerConfig.objects.conf("server_starting_mode", True) +ServerConfig.objects.conf("server_starting_mode", True) # twistd requires us to define the variable 'application' so it knows # what to execute from. application = service.Application('Evennia') -# The main evennia server program. This sets up the database +# The main evennia server program. This sets up the database # and is where we store all the other services. EVENNIA = Evennia(application) # The AMP protocol handles the communication between # the portal and the mud server. Only reason to ever deactivate -# it would be during testing and debugging. +# it would be during testing and debugging. -if AMP_ENABLED: +if AMP_ENABLED: from src.server import amp @@ -278,7 +278,7 @@ if IRC_ENABLED: # IRC channel connections - from src.comms import irc + from src.comms import irc irc.connect_all() if IMC2_ENABLED: @@ -289,10 +289,10 @@ if IMC2_ENABLED: imc2.connect_all() if RSS_ENABLED: - - # RSS feed channel connections + + # RSS feed channel connections from src.comms import rss - rss.connect_all() + rss.connect_all() # clear server startup mode ServerConfig.objects.conf("server_starting_mode", delete=True) diff --git a/src/server/serversession.py b/src/server/serversession.py index 2bd3020973..7994d0154e 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -1,13 +1,13 @@ """ -This defines a the Server's generic session object. This object represents -a connection to the outside world but don't know any details about how the +This defines a the Server's generic session object. This object represents +a connection to the outside world but don't know any details about how the connection actually happens (so it's the same for telnet, web, ssh etc). It is stored on the Server side (as opposed to protocol-specific sessions which are stored on the Portal side) """ -import time +import time from datetime import datetime from django.conf import settings from src.scripts.models import ScriptDB @@ -16,7 +16,7 @@ from src.utils import logger, utils from src.commands import cmdhandler, cmdsethandler from src.server.session import Session -IDLE_COMMAND = settings.IDLE_COMMAND +IDLE_COMMAND = settings.IDLE_COMMAND # load optional out-of-band function module OOB_FUNC_MODULE = settings.OOB_FUNC_MODULE @@ -33,14 +33,14 @@ from django.utils.translation import ugettext as _ class ServerSession(Session): """ - This class represents a player's session and is a template for - individual protocols to communicate with Evennia. + This class represents a player's session and is a template for + individual protocols to communicate with Evennia. Each player gets a session assigned to them whenever they connect to the game server. All communication between game and player goes through their session. - """ + """ def at_sync(self): """ This is called whenever a session has been resynced with the portal. @@ -48,13 +48,13 @@ class ServerSession(Session): been assigned (if applicable). Since this is often called after a server restart we need to set up - the session as it was. + the session as it was. """ if not self.logged_in: # assign the unloggedin-command set. self.cmdset = cmdsethandler.CmdSetHandler(self) self.cmdset_storage = [settings.CMDSET_UNLOGGEDIN] - self.cmdset.update(init_mode=True) + self.cmdset.update(init_mode=True) self.cmdset.update(init_mode=True) return @@ -80,29 +80,29 @@ class ServerSession(Session): self.uname = self.user.username self.logged_in = True self.conn_time = time.time() - + # Update account's last login time. - self.user.last_login = datetime.now() - self.user.save() - + self.user.last_login = datetime.now() + self.user.save() + # player init #print "at_init() - player" player.at_init() - - # Check if this is the first time the *player* logs in + + # Check if this is the first time the *player* logs in if player.db.FIRST_LOGIN: player.at_first_login() del player.db.FIRST_LOGIN - player.at_pre_login() + player.at_pre_login() character = player.character - if character: + 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 + del character.db.FIRST_LOGIN # run character login hook character.at_pre_login() @@ -110,12 +110,12 @@ class ServerSession(Session): # start (persistent) scripts on this object ScriptDB.objects.validate(obj=self.player.character) - + #add session to connected list self.sessionhandler.login(self) - # post-login hooks - player.at_post_login() + # post-login hooks + player.at_post_login() if character: character.at_post_login() @@ -125,15 +125,15 @@ class ServerSession(Session): accounting. This method is used also for non-loggedin accounts. """ - if self.logged_in: + if self.logged_in: player = self.get_player() character = self.get_character() if character: character.at_disconnect() uaccount = player.user uaccount.last_login = datetime.now() - uaccount.save() - self.logged_in = False + uaccount.save() + self.logged_in = False self.sessionhandler.disconnect(self) def get_player(self): @@ -143,8 +143,8 @@ class ServerSession(Session): if self.logged_in: return self.player else: - return None - + return None + def get_character(self): """ Returns the in-game character associated with this session. @@ -153,12 +153,12 @@ class ServerSession(Session): player = self.get_player() if player: return player.character - return None + return None def log(self, message, channel=True): """ Emits session info to the appropriate outputs and info channels. - """ + """ if channel: try: cchan = settings.CHANNEL_CONNECTINFO @@ -171,7 +171,7 @@ class ServerSession(Session): def update_session_counters(self, idle=False): """ Hit this when the user enters a command in order to update idle timers - and command counters. + and command counters. """ # Store the timestamp of the user's last command. self.cmd_last = time.time() @@ -187,24 +187,24 @@ class ServerSession(Session): """ # handle the 'idle' command if str(command_string).strip() == IDLE_COMMAND: - self.update_session_counters(idle=True) - return - + self.update_session_counters(idle=True) + return + # all other inputs, including empty inputs - character = self.get_character() - + character = self.get_character() + if character: character.execute_cmd(command_string) else: if self.logged_in: # there is no character, but we are logged in. Use player instead. - self.get_player().execute_cmd(command_string) - else: - # we are not logged in. Use the session directly + self.get_player().execute_cmd(command_string) + else: + # we are not logged in. Use the session directly # (it uses the settings.UNLOGGEDIN cmdset) cmdhandler.cmdhandler(self, command_string) - self.update_session_counters() + self.update_session_counters() def data_out(self, msg, data=None): """ @@ -218,25 +218,25 @@ class ServerSession(Session): This receives out-of-band data from the Portal. This method parses the data input (a dict) and uses - it to launch correct methods from those plugged into - the system. - + it to launch correct methods from those plugged into + the system. + data = {funcname: ( [args], {kwargs]), funcname: ( [args], {kwargs}), ...} - example: + example: data = {"get_hp": ([], {}), "update_counter", (["counter1"], {"now":True}) } """ print "server: " outdata = {} - + entity = self.get_character() if not entity: entity = self.get_player() if not entity: - entity = self + entity = self for funcname, argtuple in data.items(): # loop through the data, calling available functions. @@ -262,19 +262,19 @@ class ServerSession(Session): def __eq__(self, other): return self.address == other.address - + def __str__(self): """ String representation of the user session class. We use this a lot in the server logs. """ symbol = "" - if self.logged_in and hasattr(self, "player") and self.player: - symbol = "(#%s)" % self.player.id + if self.logged_in and hasattr(self, "player") and self.player: + symbol = "(#%s)" % self.player.id try: - address = ":".join([str(part) for part in self.address]) + address = ":".join([str(part) for part in self.address]) except Exception: - address = self.address + address = self.address return "%s%s@%s" % (self.uname, symbol, address) def __unicode__(self): @@ -298,7 +298,7 @@ class ServerSession(Session): # Dummy API hooks for use a non-loggedin operation - + def at_cmdset_get(self): "dummy hook all objects with cmdsets need to have" pass @@ -306,11 +306,11 @@ class ServerSession(Session): # 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 + 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. @@ -321,14 +321,14 @@ class ServerSession(Session): class NdbHolder(object): "Holder for storing non-persistent attributes." def all(self): - return [val for val in self.__dict__.keys() - if not val.startswith['_']] + return [val for val in self.__dict__.keys() + if not val.startswith['_']] def __getattribute__(self, key): - # return None if no matching attribute was found. + # return None if no matching attribute was found. try: return object.__getattribute__(self, key) except AttributeError: - return None + return None self._ndb_holder = NdbHolder() return self._ndb_holder #@ndb.setter @@ -348,4 +348,4 @@ class ServerSession(Session): # at this stage, so we just present a uniform API) def access(self, *args, **kwargs): "Dummy method." - return True + return True diff --git a/src/server/session.py b/src/server/session.py index 4fd6ab86cc..9fe624096e 100644 --- a/src/server/session.py +++ b/src/server/session.py @@ -1,10 +1,10 @@ """ -This defines a generic session class. All connection instances (both -on Portal and Server side) should inherit from this class. +This defines a generic session class. All connection instances (both +on Portal and Server side) should inherit from this class. """ - -import time + +import time #------------------------------------------------------------ # Server Session @@ -21,27 +21,27 @@ class Session(object): protocols that Evennia supports, like Telnet, SSH etc. The Portal session must call init_session() as part of its initialization. The respective hook methods should be connected to the methods unique for the respective - protocol so that there is a unified interface to Evennia. + protocol so that there is a unified interface to Evennia. 2) A Server session. This is the same for all connected players, regardless - of how they connect. + of how they connect. The Portal and Server have their own respective sessionhandlers. These are synced whenever new connections happen or the Server restarts etc, which means much of the same information must be stored in both places e.g. the portal can re-sync with the - server when the server reboots. + server when the server reboots. """ # names of attributes that should be affected by syncing. - _attrs_to_sync = ['protocol_key', 'address', 'suid', 'sessid', 'uid', 'uname', - 'logged_in', 'cid', 'encoding', - 'conn_time', 'cmd_last', 'cmd_last_visible', 'cmd_total', - 'server_data'] - + _attrs_to_sync = ['protocol_key', 'address', 'suid', 'sessid', 'uid', 'uname', + 'logged_in', 'cid', 'encoding', + 'conn_time', 'cmd_last', 'cmd_last_visible', 'cmd_total', + 'server_data'] + def init_session(self, protocol_key, address, sessionhandler): """ Initialize the Session. This should be called by the protocol when - a new session is established. + a new session is established. protocol_key - telnet, ssh, ssl or web address - client address sessionhandler - reference to the sessionhandler instance @@ -50,24 +50,24 @@ class Session(object): self.protocol_key = protocol_key # Protocol address tied to this session self.address = address - + # suid is used by some protocols, it's a hex key. - self.suid = None - - # unique id for this session + self.suid = None + + # unique id for this session self.sessid = 0 # no sessid yet # database id for the user connected to this session self.uid = None # user name, for easier tracking of sessions - self.uname = None + self.uname = None # if user has authenticated already or not self.logged_in = False # database id of character/object connected to this player session (if any) - self.cid = None + self.cid = None self.encoding = "utf-8" - - # session time statistics + + # session time statistics self.conn_time = time.time() self.cmd_last_visible = self.conn_time self.cmd_last = self.conn_time @@ -76,10 +76,10 @@ class Session(object): self.protocol_flags = {} self.server_data = {} - # a back-reference to the relevant sessionhandler this - # session is stored in. + # a back-reference to the relevant sessionhandler this + # session is stored in. self.sessionhandler = sessionhandler - + def get_sync_data(self): """ Return all data relevant to sync the session @@ -93,15 +93,15 @@ class Session(object): """ Takes a session dictionary, as created by get_sync_data, and loads it into the correct attributes of the session. - """ + """ for attrname, value in sessdata.items(): - self.__dict__[attrname] = value - + self.__dict__[attrname] = value + def at_sync(self): """ Called after a session has been fully synced (including - secondary operations such as setting self.player based - on uid etc). + secondary operations such as setting self.player based + on uid etc). """ pass @@ -112,13 +112,13 @@ class Session(object): generic hook called from the outside to disconnect this session should be connected to the protocols actual disconnect mechanism. """ - pass + pass def data_out(self, msg, data=None): """ - generic hook for sending data out through the protocol. Server - protocols can use this right away. Portal sessions - should overload this to format/handle the outgoing data as needed. + generic hook for sending data out through the protocol. Server + protocols can use this right away. Portal sessions + should overload this to format/handle the outgoing data as needed. """ pass @@ -126,8 +126,8 @@ class Session(object): """ hook for protocols to send incoming data to the engine. """ - pass - + pass + def oob_data_out(self, data): """ for Portal, this receives out-of-band data from Server across the AMP. @@ -141,7 +141,7 @@ class Session(object): """ for Portal, this sends out-of-band requests to Server over the AMP. for Server, this receives data from Portal. - + data is a dictionary """ pass diff --git a/src/server/sessionhandler.py b/src/server/sessionhandler.py index 9a1acf1632..50743542e4 100644 --- a/src/server/sessionhandler.py +++ b/src/server/sessionhandler.py @@ -1,33 +1,33 @@ """ -This module defines handlers for storing sessions when handles -sessions of users connecting to the server. +This module defines handlers for storing sessions when handles +sessions of users connecting to the server. There are two similar but separate stores of sessions: - ServerSessionHandler - this stores generic game sessions + ServerSessionHandler - this stores generic game sessions for the game. These sessions has no knowledge about - how they are connected to the world. + how they are connected to the world. PortalSessionHandler - this stores sessions created by twisted protocols. These are dumb connectors that handle network communication but holds no game info. - + """ import time from django.conf import settings from django.contrib.auth.models import User from src.server.models import ServerConfig -from src.utils import utils +from src.utils import utils from src.commands.cmdhandler import CMD_LOGINSTART -# AMP signals +# AMP signals PCONN = chr(1) # portal session connect PDISCONN = chr(2) # portal session disconnect PSYNC = chr(3) # portal session sync SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect +SDISCONN = chr(5) # server session disconnect SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown +SSHUTD = chr(7) # server shutdown SSYNC = chr(8) # server session sync # i18n @@ -43,7 +43,7 @@ class SessionHandler(object): """ def __init__(self): """ - Init the handler. + Init the handler. """ self.sessions = {} @@ -64,13 +64,13 @@ class SessionHandler(object): def get_all_sync_data(self): """ - Create a dictionary of sessdata dicts representing all - sessions in store. + Create a dictionary of sessdata dicts representing all + sessions in store. """ sessdict = {} for sess in self.sessions.values(): # copy all relevant data from all sessions - sessdict[sess.sessid] = sess.get_sync_data() + sessdict[sess.sessid] = sess.get_sync_data() return sessdict #------------------------------------------------------------ @@ -80,13 +80,13 @@ class SessionHandler(object): class ServerSessionHandler(SessionHandler): """ This object holds the stack of sessions active in the game at - any time. + any time. A session register with the handler in two steps, first by registering itself with the connect() method. This indicates an non-authenticated session. Whenever the session is authenticated the session together with the related player is sent to the login() - method. + method. """ @@ -94,15 +94,15 @@ class ServerSessionHandler(SessionHandler): def __init__(self): """ - Init the handler. + Init the handler. """ self.sessions = {} - self.server = None + self.server = None self.server_data = {"servername":settings.SERVERNAME} def portal_connect(self, sessid, session): """ - Called by Portal when a new session has connected. + Called by Portal when a new session has connected. Creates a new, unlogged-in game session. """ self.sessions[sessid] = session @@ -122,10 +122,10 @@ class ServerSessionHandler(SessionHandler): """ Syncing all session ids of the portal with the ones of the server. This is instantiated by the portal when reconnecting. - + sesslist is a complete list of (sessid, session) pairs, matching the list on the portal. if session was logged in, the amp handler will have logged them in before this point. - """ + """ for sess in self.sessions.values(): # we delete the old session to make sure to catch eventual lingering references. del sess @@ -136,15 +136,15 @@ class ServerSessionHandler(SessionHandler): def portal_shutdown(self): """ Called by server when shutting down the portal. - """ + """ self.server.amp_protocol.call_remote_PortalAdmin(0, operation=SSHUTD, - data="") - # server-side access methods + data="") + # server-side access methods def disconnect(self, session, reason=""): """ - Called from server side to remove session and inform portal + Called from server side to remove session and inform portal of this fact. """ session = self.sessions.get(session.sessid, None) @@ -157,7 +157,7 @@ class ServerSessionHandler(SessionHandler): data=reason) self.session_count(-1) - + def login(self, session): """ Log in the previously unloggedin session and the player we by @@ -165,22 +165,22 @@ class ServerSessionHandler(SessionHandler): assume the session to be logged in one way or another. """ # prep the session with player/user info - + if not ALLOW_MULTISESSION: # disconnect previous sessions. self.disconnect_duplicate_sessions(session) - session.logged_in = True + session.logged_in = True self.session_count(1) # sync the portal to this session sessdata = session.get_sync_data() self.server.amp_protocol.call_remote_PortalAdmin(session.sessid, operation=SLOGIN, data=sessdata) - + def session_sync(self): """ This is called by the server when it reboots. It syncs all session data - to the portal. + to the portal. """ sessdata = self.get_all_sync_data() self.server.amp_protocol.call_remote_PortalAdmin(0, @@ -192,7 +192,7 @@ class ServerSessionHandler(SessionHandler): """ Cleanly disconnect all of the connected sessions. """ - + for session in self.sessions: del session self.session_count(0) @@ -203,42 +203,42 @@ class ServerSessionHandler(SessionHandler): def disconnect_duplicate_sessions(self, curr_session, reason = _("Logged in from elsewhere. Disconnecting.") ): """ - Disconnects any existing sessions with the same game object. + Disconnects any existing sessions with the same game object. """ curr_char = curr_session.get_character() doublet_sessions = [sess for sess in self.sessions - if sess.logged_in + if sess.logged_in and sess.get_character() == curr_char and sess != curr_session] for sessid in doublet_sessions: - self.disconnect(session, reason) + self.disconnect(session, reason) self.session_count(-1) def validate_sessions(self): """ - Check all currently connected sessions (logged in and not) + Check all currently connected sessions (logged in and not) and see if any are dead. """ tcurr = time.time() reason= _("Idle timeout exceeded, disconnecting.") - for session in (session for session in self.sessions.values() - if session.logged_in and IDLE_TIMEOUT > 0 + for session in (session for session in self.sessions.values() + if session.logged_in and IDLE_TIMEOUT > 0 and (tcurr - session.cmd_last) > IDLE_TIMEOUT): self.disconnect(session, reason=reason) self.session_count(-1) - + def session_count(self, num=None): """ - Count up/down the number of connected, authenticated users. + Count up/down the number of connected, authenticated users. If num is None, the current number of sessions is returned. - num can be a positive or negative value to be added to the current count. - If 0, the counter will be reset to 0. + num can be a positive or negative value to be added to the current count. + If 0, the counter will be reset to 0. """ if num == None: - # show the current value. This also syncs it. - return int(ServerConfig.objects.conf('nr_sessions', default=0)) + # show the current value. This also syncs it. + return int(ServerConfig.objects.conf('nr_sessions', default=0)) elif num == 0: # reset value to 0 ServerConfig.objects.conf('nr_sessions', 0) @@ -255,7 +255,7 @@ class ServerSessionHandler(SessionHandler): Only logged-in players are counted here. """ return len(set(session.uid for session in self.sessions.values() if session.logged_in)) - + def sessions_from_player(self, player): """ Given a player, return any matching sessions. @@ -275,7 +275,7 @@ class ServerSessionHandler(SessionHandler): player = character.player if player: return self.sessions_from_player(player) - return None + return None def announce_all(self, message): @@ -295,15 +295,15 @@ class ServerSessionHandler(SessionHandler): def data_in(self, sessid, string="", data=""): """ Data Portal -> Server - """ - session = self.sessions.get(sessid, None) - if session: + """ + session = self.sessions.get(sessid, None) + if session: session.execute_cmd(string) # ignore 'data' argument for now; this is otherwise the place # to put custom effects on the server due to data input, e.g. - # from a custom client. - + # from a custom client. + def oob_data_in(self, sessid, data): """ OOB (Out-of-band) Data Portal -> Server @@ -327,11 +327,11 @@ class PortalSessionHandler(SessionHandler): """ This object holds the sessions connected to the portal at any time. It is synced with the server's equivalent SessionHandler over the AMP - connection. + connection. - Sessions register with the handler using the connect() method. This + Sessions register with the handler using the connect() method. This will assign a new unique sessionid to the session and send that sessid - to the server using the AMP connection. + to the server using the AMP connection. """ @@ -339,7 +339,7 @@ class PortalSessionHandler(SessionHandler): """ Init the handler """ - self.portal = None + self.portal = None self.sessions = {} self.latest_sessid = 0 self.uptime = time.time() @@ -351,19 +351,19 @@ class PortalSessionHandler(SessionHandler): Server. At this point, the AMP connection is already established. """ - self.connection_time = time.time() + self.connection_time = time.time() def connect(self, session): """ Called by protocol at first connect. This adds a not-yet authenticated session - using an ever-increasing counter for sessid. - """ + using an ever-increasing counter for sessid. + """ self.latest_sessid += 1 sessid = self.latest_sessid session.sessid = sessid sessdata = session.get_sync_data() self.sessions[sessid] = session - # sync with server-side + # sync with server-side self.portal.amp_protocol.call_remote_ServerAdmin(sessid, operation=PCONN, data=sessdata) @@ -374,23 +374,23 @@ class PortalSessionHandler(SessionHandler): sessid = session.sessid self.portal.amp_protocol.call_remote_ServerAdmin(sessid, operation=PDISCONN) - + def server_disconnect(self, sessid, reason=""): """ Called by server to force a disconnect by sessid """ session = self.sessions.get(sessid, None) if session: - session.disconnect(reason) - del session + session.disconnect(reason) + del session def server_disconnect_all(self, reason=""): """ Called by server when forcing a clean disconnect for everyone. """ - for session in self.sessions.values(): + for session in self.sessions.values(): session.disconnect(reason) - del session + del session def count_loggedin(self, include_unloggedin=False): @@ -398,22 +398,22 @@ class PortalSessionHandler(SessionHandler): Count loggedin connections, alternatively count all connections. """ return len(self.get_sessions(include_unloggedin=include_unloggedin)) - + def session_from_suid(self, suid): """ Given a session id, retrieve the session (this is primarily intended to be called by web clients) """ - return [sess for sess in self.get_sessions(include_unloggedin=True) + return [sess for sess in self.get_sessions(include_unloggedin=True) if hasattr(sess, 'suid') and sess.suid == suid] def data_in(self, session, string="", data=""): """ - Called by portal sessions for relaying data coming - in from the protocol to the server. data is - serialized before passed on. - """ + Called by portal sessions for relaying data coming + in from the protocol to the server. data is + serialized before passed on. + """ self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid, msg=string, data=data) @@ -426,12 +426,12 @@ class PortalSessionHandler(SessionHandler): def data_out(self, sessid, string="", data=""): """ - Called by server for having the portal relay messages and data - to the correct session protocol. + Called by server for having the portal relay messages and data + to the correct session protocol. """ session = self.sessions.get(sessid, None) if session: - session.data_out(string, data=data) + session.data_out(string, data=data) def oob_data_in(self, session, data): """ diff --git a/src/server/ssh.py b/src/server/ssh.py index e53fa56774..ec5f974b77 100644 --- a/src/server/ssh.py +++ b/src/server/ssh.py @@ -6,7 +6,7 @@ This depends on a generic session module that implements the actual login procedure of the game, tracks sessions etc. -Using standard ssh client, +Using standard ssh client, """ import os @@ -65,11 +65,11 @@ class SshProtocol(Manhole, session.Session): # initialize the session client_address = self.getClientAddress() - self.init_session("ssh", client_address, self.cfactory.sessionhandler) + self.init_session("ssh", client_address, self.cfactory.sessionhandler) - # since we might have authenticated already, we might set this here. + # since we might have authenticated already, we might set this here. if self.authenticated_player: - self.logged_in = True + self.logged_in = True self.uid = self.authenticated_player.user.id self.sessionhandler.connect(self) @@ -82,8 +82,8 @@ class SshProtocol(Manhole, session.Session): self.keyHandlers[CTRL_C] = self.handle_INT self.keyHandlers[CTRL_D] = self.handle_EOF self.keyHandlers[CTRL_L] = self.handle_FF - self.keyHandlers[CTRL_BACKSLASH] = self.handle_QUIT - + self.keyHandlers[CTRL_BACKSLASH] = self.handle_QUIT + # initalize def handle_INT(self): @@ -128,8 +128,8 @@ class SshProtocol(Manhole, session.Session): def connectionLost(self, reason=None): """ This is executed when the connection is lost for - whatever reason. It can also be called directly, - from the disconnect method. + whatever reason. It can also be called directly, + from the disconnect method. """ insults.TerminalProtocol.connectionLost(self, reason) @@ -186,7 +186,7 @@ class SshProtocol(Manhole, session.Session): self.lineSend(str(e)) return nomarkup = False - raw = False + raw = False if type(data) == dict: # check if we want escape codes to go through unparsed. raw = data.get("raw", False) @@ -230,7 +230,7 @@ class PlayerDBPasswordChecker(object): username = up.username password = up.password player = PlayerDB.objects.get_player_from_name(username) - res = (None, self.factory) + res = (None, self.factory) if player and player.user.check_password(password): res = (player, self.factory) return defer.succeed(res) @@ -290,13 +290,13 @@ class TerminalSessionTransport_getPeer: def getKeyPair(pubkeyfile, privkeyfile): """ This function looks for RSA keypair files in the current directory. If they - do not exist, the keypair is created. + do not exist, the keypair is created. """ if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)): # No keypair exists. Generate a new RSA keypair print _(" Generating SSH RSA keypair ..."), - from Crypto.PublicKey import RSA + from Crypto.PublicKey import RSA KEY_LENGTH = 1024 rsaKey = Key(RSA.generate(KEY_LENGTH)) diff --git a/src/server/ssl.py b/src/server/ssl.py index 9703c7795d..433edd0273 100644 --- a/src/server/ssl.py +++ b/src/server/ssl.py @@ -1,6 +1,6 @@ """ -This is a simple context factory for auto-creating -SSL keys and certificates. +This is a simple context factory for auto-creating +SSL keys and certificates. """ import os, sys @@ -16,21 +16,21 @@ from src.server.telnet import TelnetProtocol class SSLProtocol(TelnetProtocol): """ Communication is the same as telnet, except data transfer - is done with encryption. + is done with encryption. """ pass def verify_SSL_key_and_cert(keyfile, certfile): """ This function looks for RSA key and certificate in the current - directory. If files ssl.key and ssl.cert does not exist, they + directory. If files ssl.key and ssl.cert does not exist, they are created. """ if not (os.path.exists(keyfile) and os.path.exists(certfile)): - # key/cert does not exist. Create. + # key/cert does not exist. Create. import subprocess - from Crypto.PublicKey import RSA + from Crypto.PublicKey import RSA from twisted.conch.ssh.keys import Key print _(" Creating SSL key and certificate ... "), @@ -39,16 +39,16 @@ def verify_SSL_key_and_cert(keyfile, certfile): # create the RSA key and store it. KEY_LENGTH = 1024 rsaKey = Key(RSA.generate(KEY_LENGTH)) - keyString = rsaKey.toString(type="OPENSSH") + keyString = rsaKey.toString(type="OPENSSH") file(keyfile, 'w+b').write(keyString) - except Exception,e: + except Exception,e: print _("rsaKey error: %(e)s\n WARNING: Evennia could not auto-generate SSL private key.") % {'e': e} print _("If this error persists, create game/%(keyfile)s yourself using third-party tools.") % {'keyfile': keyfile} sys.exit(5) - + # try to create the certificate - CERT_EXPIRE = 365 * 20 # twenty years validity - # default: + CERT_EXPIRE = 365 * 20 # twenty years validity + # default: #openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300 exestring = "openssl req -new -x509 -key %s -out %s -days %s" % (keyfile, certfile, CERT_EXPIRE) #print "exestring:", exestring @@ -58,9 +58,9 @@ def verify_SSL_key_and_cert(keyfile, certfile): print " %s\n" % e print _(" Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s.") % {'cert': certfile} print _(" A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid") % {'cert': certfile} - print _(" for your operating system.") + print _(" for your operating system.") print _(" Example (linux, using the openssl program): ") - print " %s" % exestring + print " %s" % exestring sys.exit(5) print "done." diff --git a/src/server/telnet.py b/src/server/telnet.py index 77365bb6cb..42357dbd07 100644 --- a/src/server/telnet.py +++ b/src/server/telnet.py @@ -2,8 +2,8 @@ This module implements the telnet protocol. This depends on a generic session module that implements -the actual login procedure of the game, tracks -sessions etc. +the actual login procedure of the game, tracks +sessions etc. """ @@ -11,44 +11,44 @@ from twisted.conch.telnet import Telnet, StatefulTelnetProtocol, IAC, LINEMODE, from src.server.session import Session from src.server import ttype, mssp from src.server.mccp import Mccp, mccp_compress, MCCP -from src.utils import utils, ansi +from src.utils import utils, ansi class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): """ Each player connecting over telnet (ie using most traditional mud clients) gets a telnet protocol instance assigned to them. All communication between game and player goes through here. - """ + """ def connectionMade(self): """ - This is called when the connection is first - established. - """ + This is called when the connection is first + established. + """ # initialize the session - client_address = self.transport.client + client_address = self.transport.client self.init_session("telnet", client_address, self.factory.sessionhandler) # negotiate mccp (data compression) - self.mccp = Mccp(self) - + self.mccp = Mccp(self) + # negotiate ttype (client info) self.ttype = ttype.Ttype(self) # negotiate mssp (crawler communication) self.mssp = mssp.Mssp(self) - - # add this new connection to sessionhandler so - # the Server becomes aware of it. - self.sessionhandler.connect(self) - - def enableRemote(self, option): + # add this new connection to sessionhandler so + # the Server becomes aware of it. + self.sessionhandler.connect(self) + + + def enableRemote(self, option): """ This sets up the options we allow for this protocol. """ return (option == LINEMODE or option == ttype.TTYPE or - option == MCCP or + option == MCCP or option == mssp.MSSP) def enableLocal(self, option): @@ -60,18 +60,18 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): def disableLocal(self, option): if option == MCCP: self.mccp.no_mccp(option) - return True + return True else: return super(TelnetProtocol, self).disableLocal(option) - - + + def connectionLost(self, reason): """ - This is executed when the connection is lost for + This is executed when the connection is lost for whatever reason. It can also be called directly, from the disconnect method - """ - self.sessionhandler.disconnect(self) + """ + self.sessionhandler.disconnect(self) self.transport.loseConnection() def dataReceived(self, data): @@ -83,7 +83,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): # print "dataRcv:", data, # try: # for b in data: - # print ord(b), + # print ord(b), # print "" # except Exception, e: # print str(e) + ":", str(data) @@ -91,19 +91,19 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): if data and data[0] == IAC: try: super(TelnetProtocol, self).dataReceived(data) - return + return except Exception: pass StatefulTelnetProtocol.dataReceived(self, data) - + def _write(self, data): "hook overloading the one used in plain telnet" - #print "_write (%s): %s" % (self.state, " ".join(str(ord(c)) for c in data)) + #print "_write (%s): %s" % (self.state, " ".join(str(ord(c)) for c in data)) data = data.replace('\n', '\r\n') super(TelnetProtocol, self)._write(mccp_compress(self, data)) def sendLine(self, line): - "hook overloading the one used by linereceiver" + "hook overloading the one used by linereceiver" #print "sendLine (%s):\n%s" % (self.state, line) #escape IAC in line mode, and correctly add \r\n line += self.delimiter @@ -112,17 +112,17 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): def lineReceived(self, string): """ - Telnet method called when data is coming in over the telnet + Telnet method called when data is coming in over the telnet connection. We pass it on to the game engine directly. - """ + """ self.sessionhandler.data_in(self, string) - - # Session hooks + + # Session hooks def disconnect(self, reason=None): """ - generic hook for the engine to call in order to + generic hook for the engine to call in order to disconnect this protocol. """ if reason: @@ -131,25 +131,25 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): def data_out(self, string, data=None): """ - generic hook method for engine to call in order to send data - through the telnet connection. - Data Evennia -> Player. + generic hook method for engine to call in order to send data + through the telnet connection. + Data Evennia -> Player. data argument may contain a dict with output flags. """ - try: - string = utils.to_str(string, encoding=self.encoding) - except Exception, e: - self.sendLine(str(e)) - return + try: + string = utils.to_str(string, encoding=self.encoding) + except Exception, e: + self.sendLine(str(e)) + return ttype = self.protocol_flags.get('TTYPE', {}) nomarkup = not (ttype.get('256 COLORS') or ttype.get('ANSI') or not ttype.get("init_done")) raw = False - if type(data) == dict: + if type(data) == dict: # check if we want escape codes to go through unparsed. raw = data.get("raw", False) # check if we want to remove all markup (TTYPE override) nomarkup = data.get("nomarkup", False) - if raw: - self.sendLine(string) + if raw: + self.sendLine(string) else: self.sendLine(ansi.parse_ansi(string, strip_ansi=nomarkup, xterm256=ttype.get('256 COLORS'))) diff --git a/src/server/ttype.py b/src/server/ttype.py index 095c7eee63..fdf41e0d89 100644 --- a/src/server/ttype.py +++ b/src/server/ttype.py @@ -17,18 +17,18 @@ IS = chr(0) SEND = chr(1) # terminal capabilities and their codes -MTTS = [(128,'PROXY'), - (64, 'SCREEN READER'), - (32, 'OSC COLOR PALETTE'), - (16, 'MOUSE TRACKING'), - (8, '256 COLORS'), +MTTS = [(128,'PROXY'), + (64, 'SCREEN READER'), + (32, 'OSC COLOR PALETTE'), + (16, 'MOUSE TRACKING'), + (8, '256 COLORS'), (4, 'UTF-8'), (2, 'VT100'), (1, 'ANSI')] class Ttype(object): """ - Handles ttype negotiations. Called and initiated by the + Handles ttype negotiations. Called and initiated by the telnet protocol. """ def __init__(self, protocol): @@ -39,26 +39,26 @@ class Ttype(object): the ttype_step indicates how far in the data retrieval we've gotten. """ - self.ttype_step = 0 + self.ttype_step = 0 self.protocol = protocol self.protocol.protocol_flags['TTYPE'] = {"init_done":False} # setup protocol to handle ttype initialization and negotiation - self.protocol.negotiationMap[TTYPE] = self.do_ttype + self.protocol.negotiationMap[TTYPE] = self.do_ttype # ask if client will ttype, connect callback if it does. self.protocol.will(TTYPE).addCallbacks(self.do_ttype, self.no_ttype) - + def no_ttype(self, option): """ - Callback if ttype is not supported by client. + Callback if ttype is not supported by client. """ - self.protocol.protocol_flags['TTYPE'] = False + self.protocol.protocol_flags['TTYPE'] = False def do_ttype(self, option): """ - Handles negotiation of the ttype protocol once the - client has confirmed that it supports the ttype - protocol. + Handles negotiation of the ttype protocol once the + client has confirmed that it supports the ttype + protocol. The negotiation proceeds in several steps, each returning a certain piece of information about the client. All data is @@ -66,15 +66,15 @@ class Ttype(object): """ if self.protocol.protocol_flags['TTYPE']['init_done']: - return + return self.ttype_step += 1 - if self.ttype_step == 1: - # set up info storage and initialize subnegotiation + if self.ttype_step == 1: + # set up info storage and initialize subnegotiation self.protocol.requestNegotiation(TTYPE, SEND) else: - # receive data + # receive data option = "".join(option).lstrip(IS) if self.ttype_step == 2: self.protocol.protocol_flags['TTYPE']['CLIENTNAME'] = option @@ -82,17 +82,16 @@ class Ttype(object): elif self.ttype_step == 3: self.protocol.protocol_flags['TTYPE']['TERM'] = option self.protocol.requestNegotiation(TTYPE, SEND) - elif self.ttype_step == 4: + elif self.ttype_step == 4: option = int(option.strip('MTTS ')) - self.protocol.protocol_flags['TTYPE']['MTTS'] = option - for codenum, standard in MTTS: + self.protocol.protocol_flags['TTYPE']['MTTS'] = option + for codenum, standard in MTTS: if option == 0: - break + break status = option % codenum < option self.protocol.protocol_flags['TTYPE'][standard] = status - if status: + if status: option = option % codenum self.protocol.protocol_flags['TTYPE']['init_done'] = True #print "ttype results:", self.protocol.protocol_flags['TTYPE'] - diff --git a/src/server/webclient.py b/src/server/webclient.py index c4154bb1d2..015492aef7 100644 --- a/src/server/webclient.py +++ b/src/server/webclient.py @@ -4,17 +4,17 @@ Web client server resource. The Evennia web client consists of two components running on twisted and django. They are both a part of the Evennia website url tree (so the testing website might be located -on http://localhost:8000/, whereas the webclient can be -found on http://localhost:8000/webclient.) +on http://localhost:8000/, whereas the webclient can be +found on http://localhost:8000/webclient.) /webclient - this url is handled through django's template system and serves the html page for the client itself along with its javascript chat program. /webclientdata - this url is called by the ajax chat using POST requests (long-polling when necessary) - The WebClient resource in this module will - handle these requests and act as a gateway - to sessions connected over the webclient. + The WebClient resource in this module will + handle these requests and act as a gateway + to sessions connected over the webclient. """ import time from hashlib import md5 @@ -25,7 +25,7 @@ from twisted.internet import defer, reactor from django.utils import simplejson from django.utils.functional import Promise from django.utils.encoding import force_unicode -from django.conf import settings +from django.conf import settings from src.utils import utils, logger, ansi from src.utils.text2html import parse_html from src.server import session @@ -34,7 +34,7 @@ SERVERNAME = settings.SERVERNAME ENCODINGS = settings.ENCODINGS # defining a simple json encoder for returning -# django data to the client. Might need to +# django data to the client. Might need to # extend this if one wants to send more # complex database objects too. @@ -51,36 +51,36 @@ def jsonify(obj): # WebClient resource - this is called by the ajax client # using POST requests to /webclientdata. # - + class WebClient(resource.Resource): """ - An ajax/comet long-polling transport + An ajax/comet long-polling transport """ - isLeaf = True + isLeaf = True allowedMethods = ('POST',) def __init__(self): self.requests = {} self.databuffer = {} - + def getChild(self, path, request): """ This is the place to put dynamic content. """ - return self - + return self + def _responseFailed(self, failure, suid, request): - "callback if a request is lost/timed out" + "callback if a request is lost/timed out" try: self.requests.get(suid, []).remove(request) except ValueError: - pass - + pass + def lineSend(self, suid, string, data=None): """ This adds the data to the buffer and/or sends it to the client as soon as possible. - """ + """ requests = self.requests.get(suid, None) if requests: request = requests.pop(0) @@ -88,22 +88,22 @@ class WebClient(resource.Resource): request.write(jsonify({'msg':string, 'data':data})) request.finish() self.requests[suid] = requests - else: + else: # no waiting request. Store data in buffer dataentries = self.databuffer.get(suid, []) dataentries.append(jsonify({'msg':string, 'data':data})) self.databuffer[suid] = dataentries - + def client_disconnect(self, suid): """ Disconnect session with given suid. - """ + """ if self.requests.has_key(suid): for request in self.requests.get(suid, []): request.finish() del self.requests[suid] if self.databuffer.has_key(suid): - del self.databuffer[suid] + del self.databuffer[suid] def mode_init(self, request): """ @@ -120,10 +120,10 @@ class WebClient(resource.Resource): # creating a unique id hash string suid = md5(str(time.time())).hexdigest() self.requests[suid] = [] - self.databuffer[suid] = [] + self.databuffer[suid] = [] sess = WebClientSession() - sess.client = self + sess.client = self sess.init_session("comet", remote_addr, self.sessionhandler) sess.suid = suid sess.sessionhandler.connect(sess) @@ -154,22 +154,22 @@ class WebClient(resource.Resource): available. """ suid = request.args.get('suid', ['0'])[0] - if suid == '0': + if suid == '0': return '' - + dataentries = self.databuffer.get(suid, []) if dataentries: return dataentries.pop(0) reqlist = self.requests.get(suid, []) request.notifyFinish().addErrback(self._responseFailed, suid, request) - reqlist.append(request) + reqlist.append(request) self.requests[suid] = reqlist return server.NOT_DONE_YET def mode_close(self, request): """ This is called by render_POST when the client is signalling - that it is about to be closed. + that it is about to be closed. """ suid = request.args.get('suid', ['0'])[0] if suid == '0': @@ -184,8 +184,8 @@ class WebClient(resource.Resource): initializing or sending/receving data through the request. It uses a long-polling mechanism to avoid sending data unless there is actual data available. - """ - dmode = request.args.get('mode', [None])[0] + """ + dmode = request.args.get('mode', [None])[0] if dmode == 'init': # startup. Setup the server. return self.mode_init(request) @@ -201,11 +201,11 @@ class WebClient(resource.Resource): else: # this should not happen if client sends valid data. return '' - + +# +# A session type handling communication over the +# web client interface. # -# A session type handling communication over the -# web client interface. -# class WebClientSession(session.Session): """ @@ -215,38 +215,38 @@ class WebClientSession(session.Session): def disconnect(self, reason=None): """ Disconnect from server - """ + """ if reason: self.client.lineSend(self.suid, reason) self.client.client_disconnect(self.suid) def data_out(self, string='', data=None): """ - Data Evennia -> Player access hook. + Data Evennia -> Player access hook. data argument may be used depending on - the client-server implementation. + the client-server implementation. """ - + if data: # treat data? pass # string handling is similar to telnet try: - string = utils.to_str(string, encoding=self.encoding) - + string = utils.to_str(string, encoding=self.encoding) + nomarkup = False - raw = False + raw = False if type(data) == dict: # check if we want escape codes to go through unparsed. raw = data.get("raw", False) - # check if we want to remove all markup - nomarkup = data.get("nomarkup", False) + # check if we want to remove all markup + nomarkup = data.get("nomarkup", False) if raw: self.client.lineSend(self.suid, string) else: self.client.lineSend(self.suid, parse_html(ansi.parse_ansi(string, strip_ansi=nomarkup))) - return - except Exception, e: + return + except Exception, e: logger.log_trace() diff --git a/src/server/webserver.py b/src/server/webserver.py index e17ac3bddd..14774c27aa 100644 --- a/src/server/webserver.py +++ b/src/server/webserver.py @@ -14,7 +14,7 @@ a great example/aid on how to do this.) from twisted.web import resource from twisted.python import threadpool from twisted.internet import reactor -from twisted.application import service, internet +from twisted.application import service, internet from twisted.web.wsgi import WSGIResource from django.core.handlers.wsgi import WSGIHandler @@ -26,19 +26,19 @@ from django.core.handlers.wsgi import WSGIHandler class DjangoWebRoot(resource.Resource): """ This creates a web root (/) that Django - understands by tweaking the way the - child instancee are recognized. + understands by tweaking the way the + child instancee are recognized. """ def __init__(self, pool): """ Setup the django+twisted resource """ - resource.Resource.__init__(self) + resource.Resource.__init__(self) self.wsgi_resource = WSGIResource(reactor, pool , WSGIHandler()) def getChild(self, path, request): """ - To make things work we nudge the + To make things work we nudge the url tree to make this the root. """ path0 = request.prepath.pop(0) @@ -62,9 +62,9 @@ class WSGIWebServer(internet.TCPServer): internet.TCPServer.__init__(self, *args, **kwargs) def startService(self): "Start the pool after the service" - internet.TCPServer.startService(self) - self.pool.start() - def stopService(self): + internet.TCPServer.startService(self) + self.pool.start() + def stopService(self): "Safely stop the pool after service stop." - internet.TCPServer.stopService(self) + internet.TCPServer.stopService(self) self.pool.stop() diff --git a/src/settings_default.py b/src/settings_default.py index ad44133bcb..bf04b32696 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -16,19 +16,19 @@ always be sure of what you have changed and what is default behaviour. import os ################################################### -# Evennia base server config +# Evennia base server config ################################################### # This is the name of your game. Make it catchy! -SERVERNAME = "Evennia" +SERVERNAME = "Evennia" # Activate telnet service -TELNET_ENABLED = True +TELNET_ENABLED = True # A list of ports the Evennia telnet server listens on # Can be one or many. TELNET_PORTS = [4000] # Interface addresses to listen to. If 0.0.0.0, listen to all. TELNET_INTERFACES = ['0.0.0.0'] -# Start the evennia django+twisted webserver so you can +# Start the evennia django+twisted webserver so you can # browse the evennia website and the admin interface # (Obs - further web configuration can be found below # in the section 'Config for Django web features') @@ -42,21 +42,21 @@ WEBSERVER_INTERFACES = ['0.0.0.0'] WEBCLIENT_ENABLED = True # Activate SSH protocol (SecureShell) SSH_ENABLED = False -# Ports to use for SSH +# Ports to use for SSH SSH_PORTS = [8022] # Interface addresses to listen to. If 0.0.0.0, listen to all. SSH_INTERFACES = ['0.0.0.0'] # Actiave SSL protocol (SecureSocketLibrary) SSL_ENABLED = False -# Ports to use for SSL +# Ports to use for SSL SSL_PORTS = [4001] # Interface addresses to listen to. If 0.0.0.0, listen to all. SSL_INTERFACES = ['0.0.0.0'] # If multisessions are allowed, a user can log into the game # from several different computers/clients at the same time. -# All feedback from the game will be echoed to all sessions. +# All feedback from the game will be echoed to all sessions. # If false, only one session is allowed, all other are logged off -# when a new connects. +# when a new connects. ALLOW_MULTISESSION = True # Make this unique, and don't share it with anybody. # NOTE: If you change this after creating any accounts, your users won't be @@ -72,8 +72,8 @@ GAME_DIR = os.path.join(BASE_PATH, 'game') LOG_DIR = os.path.join(GAME_DIR, 'logs') SERVER_LOG_FILE = os.path.join(LOG_DIR, 'server.log') PORTAL_LOG_FILE = os.path.join(LOG_DIR, 'portal.log') -# Where to log server requests to the web server. This is VERY spammy, so this -# file should be removed at regular intervals. +# Where to log server requests to the web server. This is VERY spammy, so this +# file should be removed at regular intervals. HTTP_LOG_FILE = os.path.join(LOG_DIR, 'http_requests.log') # Local time zone for this installation. All choices can be found here: # http://www.postgresql.org/docs/8.0/interactive/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE @@ -81,57 +81,57 @@ TIME_ZONE = 'UTC' # Language code for this installation. All choices can be found here: # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes LANGUAGE_CODE = 'en-us' -# Should the default MUX help files be imported? This might be -# interesting to developers for reference, but is frustrating to users -# since it creates a lot of help entries that has nothing to do +# Should the default MUX help files be imported? This might be +# interesting to developers for reference, but is frustrating to users +# since it creates a lot of help entries that has nothing to do # with what is actually available in the game. -IMPORT_MUX_HELP = False +IMPORT_MUX_HELP = False # How long time (in seconds) a user may idle before being logged # out. This can be set as big as desired. A user may avoid being # thrown off by sending the empty system command 'idle' to the server # at regular intervals. Set <=0 to deactivate idle timout completely. IDLE_TIMEOUT = 3600 -# The idle command can be sent to keep your session active without actually +# The idle command can be sent to keep your session active without actually # having to spam normal commands regularly. It gives no feedback, only updates # the idle timer. IDLE_COMMAND = "idle" -# The set of encodings tried. A Player object may set an attribute "encoding" on +# The set of encodings tried. A Player object may set an attribute "encoding" on # itself to match the client used. If not set, or wrong encoding is -# given, this list is tried, in order, aborting on the first match. +# given, this list is tried, in order, aborting on the first match. # Add sets for languages/regions your players are likely to use. # (see http://en.wikipedia.org/wiki/Character_encoding) ENCODINGS = ["utf-8", "latin-1", "ISO-8859-1"] -# The game server opens an AMP port so that the portal can +# The game server opens an AMP port so that the portal can # communicate with it. This is an internal functionality of Evennia, usually -# operating between the two processes on the same machine. Don't change unless -# you know what you are doing. +# operating between the two processes on the same machine. Don't change unless +# you know what you are doing. AMP_HOST = 'localhost' AMP_PORT = 5000 ################################################### -# Evennia Database config +# Evennia Database config ################################################### -# Database config syntax for Django 1.2+. You can add several -# database engines in the dictionary (untested). +# Database config syntax for Django 1.2+. You can add several +# database engines in the dictionary (untested). # ENGINE - path to the the database backend (replace # sqlite3 in the example with the one you want. -# Supported database engines are +# Supported database engines are # 'postgresql_psycopg2', 'postgresql', 'mysql', # 'sqlite3' and 'oracle'). # NAME - database name, or path the db file for sqlite3 # USER - db admin (unused in sqlite3) # PASSWORD - db admin password (unused in sqlite3) # HOST - empty string is localhost (unused in sqlite3) -# PORT - empty string defaults to localhost (unused in sqlite3) +# PORT - empty string defaults to localhost (unused in sqlite3) DATABASES = { 'default':{ - 'ENGINE':'django.db.backends.sqlite3', - 'NAME':os.path.join(GAME_DIR, 'evennia.db3'), + 'ENGINE':'django.db.backends.sqlite3', + 'NAME':os.path.join(GAME_DIR, 'evennia.db3'), 'USER':'', 'PASSWORD':'', 'HOST':'', - 'PORT':'' + 'PORT':'' }} # Engine Config style for Django versions < 1.2. See above. DATABASE_ENGINE = 'sqlite3' @@ -142,10 +142,10 @@ DATABASE_HOST = '' DATABASE_PORT = '' ################################################### -# Evennia pluggable modules +# Evennia pluggable modules ################################################### -# An alternate command parser module to use +# An alternate command parser module to use COMMAND_PARSER = "src.commands.cmdparser.cmdparser" # The handler that outputs errors when searching # objects using object.search(). @@ -154,25 +154,25 @@ SEARCH_AT_RESULT = "src.commands.cmdparser.at_search_result" # object matches (so you can separate between same-named # objects without using dbrefs). SEARCH_AT_MULTIMATCH_INPUT = "src.commands.cmdparser.at_multimatch_input" -# The module holding text strings for the connection screen. -# This module should contain one or more variables +# The module holding text strings for the connection screen. +# This module should contain one or more variables # with strings defining the look of the screen. CONNECTION_SCREEN_MODULE = "src.commands.connection_screen" # An option al module that, if existing, must hold a function # named at_initial_setup(). This hook method can be used to customize # the server's initial setup sequence (the very first startup of the system). -# The check will fail quietly if module doesn't exist or fails to load. +# The check will fail quietly if module doesn't exist or fails to load. AT_INITIAL_SETUP_HOOK_MODULE = "" # Module holding at_server_start(), at_server_reload() and # at_server_stop() methods. These methods will be called every time # the server starts, reloads and resets/stops. AT_SERVER_STARTSTOP_MODULE = ""# Module holding server-side functions for out-of-band protocols to call. OOB_FUNC_MODULE = "" -# Module holding MSSP meta data +# Module holding MSSP meta data MSSP_META_MODULE = "" ################################################### -# Default command sets +# Default command sets ################################################### # Note that with the exception of the unloggedin set (which is not # stored anywhere), changing these paths will only affect NEW created @@ -211,9 +211,9 @@ BASE_ROOM_TYPECLASS = "src.objects.objects.Room" BASE_EXIT_TYPECLASS = "src.objects.objects.Exit" # Typeclass for Scripts (fallback) BASE_SCRIPT_TYPECLASS = "src.scripts.scripts.DoNothing" -# The home location for new characters. This must be a unique +# The home location for new characters. This must be a unique # dbref (default is Limbo #2). If you want more advanced control over -# start locations, copy the "create" command from +# start locations, copy the "create" command from # src/commands/default/unloggedin.py and customize. CHARACTER_DEFAULT_HOME = "2" @@ -221,7 +221,7 @@ CHARACTER_DEFAULT_HOME = "2" # Batch processors ################################################### -# Python path to a directory to be searched for batch scripts +# Python path to a directory to be searched for batch scripts # for the batch processors (.ev and/or .py files). BASE_BATCHPROCESS_PATHS = ['game.gamesrc.world', 'contrib'] @@ -236,8 +236,8 @@ BASE_BATCHPROCESS_PATHS = ['game.gamesrc.world', 'contrib'] #The time factor dictates if the game world runs faster (timefactor>1) # or slower (timefactor<1) than the real world. -TIME_FACTOR = 2.0 -# The tick is the smallest unit of time in the game. Smallest value is 1s. +TIME_FACTOR = 2.0 +# The tick is the smallest unit of time in the game. Smallest value is 1s. TIME_TICK = 1.0 # These measures might or might not make sense to your game world. TIME_MIN_PER_HOUR = 60 @@ -248,7 +248,7 @@ TIME_MONTH_PER_YEAR = 12 ################################################### -# In-Game access +# In-Game access ################################################### # The access hiearchy, in climbing order. A higher permission in the @@ -268,7 +268,7 @@ LOCK_FUNC_MODULES = ("src.locks.lockfuncs",) # Defines a dict with one key for each from-start # channel. Each key points to a tuple containing # (name, aliases, description, locks) -# where aliases may be a tuple too, and locks is +# where aliases may be a tuple too, and locks is # a valid lockstring definition. # Default user channel for communication CHANNEL_PUBLIC = ("Public", ('ooc',), 'Public discussion', @@ -281,17 +281,17 @@ CHANNEL_CONNECTINFO = ("MUDconnections", '', 'Connection log', "control:perm(Immortals);listen:perm(Wizards);send:false()") ################################################### -# External Channel connections +# External Channel connections ################################################### # Note: You do *not* have to make your MUD open to # the public to use the external connections, they # operate as long as you have an internet connection, -# just like stand-alone chat clients. IRC and IMC2 -# requires that you have twisted.words installed. +# just like stand-alone chat clients. IRC and IMC2 +# requires that you have twisted.words installed. -# Evennia can connect to external IRC channels and -# echo what is said on the channel to IRC and vice +# Evennia can connect to external IRC channels and +# echo what is said on the channel to IRC and vice # versa. Obs - make sure the IRC network allows bots. # When enabled, command @irc2chan will be available in-game IRC_ENABLED = False @@ -307,7 +307,7 @@ IRC_ENABLED = False # command @imc2chan becomes available in-game and allows you to # connect Evennia channels to IMC channels on the network. The Evennia # discussion channel 'ievennia' is on server01.mudbytes.net:5000. -IMC2_ENABLED = False +IMC2_ENABLED = False IMC2_NETWORK = "server01.mudbytes.net" IMC2_PORT = 5000 IMC2_CLIENT_PWD = "" @@ -316,7 +316,7 @@ IMC2_SERVER_PWD = "" # an in-game channel. The channel will be updated when the rss feed # updates. Use @rss2chan in game to connect if this setting is # active. OBS: RSS support requires the python-feedparser package to -# be installed (through package manager or from the website +# be installed (through package manager or from the website # http://code.google.com/p/feedparser/) RSS_ENABLED=False RSS_UPDATE_INTERVAL = 60*10 # 10 minutes @@ -366,7 +366,7 @@ SESSION_EXPIRE_AT_BROWSER_CLOSE = False USE_I18N = False # Where to find locales (no need to change this, most likely) LOCALE_PATHS = ["../locale/"] -# This should be turned off unless you want to do tests with Django's +# This should be turned off unless you want to do tests with Django's # development webserver (normally Evennia runs its own server) SERVE_MEDIA = False # The master urlconf file that contains all of the sub-branches to the @@ -383,7 +383,7 @@ LOGOUT_URL = '/accounts/login' MEDIA_URL = '/media/' # URL prefix for admin media -- CSS, JavaScript and images. Make sure # to use a trailing slash. Django1.4+ will look for admin files under -# STATIC_URL/admin. +# STATIC_URL/admin. STATIC_URL = '/media/' ADMIN_MEDIA_PREFIX = STATIC_URL + "admin/" # needed for backwards compatibility django < 1.4 # The name of the currently selected web template. This corresponds to the @@ -431,26 +431,26 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.admindocs', 'django.contrib.flatpages', - 'src.server', + 'src.server', 'src.players', 'src.objects', - 'src.comms', + 'src.comms', 'src.help', 'src.scripts', 'src.web.news', 'src.web.website',) # The user profile extends the User object with more functionality; -# This should usually not be changed. +# This should usually not be changed. AUTH_PROFILE_MODULE = "players.PlayerDB" # Use a custom test runner that just tests Evennia-specific apps. TEST_RUNNER = 'src.utils.test_utils.EvenniaTestSuiteRunner' ################################################### -# Django extensions +# Django extensions ################################################### # Django extesions are useful third-party tools that are not -# always included in the default django distro. +# always included in the default django distro. try: import django_extensions INSTALLED_APPS = INSTALLED_APPS + ('django_extensions',)