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