More whitespace cleanup.
This commit is contained in:
parent
c0322c9eae
commit
45c5be8468
43 changed files with 1116 additions and 1131 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <email> <password>{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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <home>, they don't need to be removed here.
|
||||
inside a deleted object are automatically moved to their <home>, they don't need to be removed here.
|
||||
|
||||
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
|
||||
at_cmdset_get() - this is called just before the command handler requests a cmdset from this object
|
||||
at_first_login() - (player-controlled objects only) called once, the very first time user logs in.
|
||||
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
|
||||
at_cmdset_get() - this is called just before the command handler requests a cmdset from this object
|
||||
at_first_login() - (player-controlled objects only) called once, the very first time user logs in.
|
||||
at_pre_login() - (player-controlled objects only) called every time the user connects, after they have identified, before other setup
|
||||
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world.
|
||||
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world.
|
||||
at_disconnect() - (player-controlled objects only) called just before the user disconnects (or goes linkless)
|
||||
at_server_reload() - called before server is reloaded
|
||||
at_server_shutdown() - called just before server is fully shut down
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
# <objname>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
|
||||
# <objname>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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
114
game/runner.py
114
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 <filename>.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():
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
||||
|
|
|
|||
|
|
@ -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')))
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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',)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue