This commit is contained in:
Griatch 2011-11-11 01:20:51 +01:00
commit ce0e3c4857
32 changed files with 1208 additions and 166 deletions

View file

@ -8,9 +8,7 @@ command line. The process is as follows:
2) The system checks the state of the caller - loggedin or not
3) If no command string was supplied, we search the merged cmdset for system command CMD_NOINPUT
and branches to execute that. --> Finished
4) Depending on the login/not state, it collects cmdsets from different sources:
not logged in - uses the single cmdset defined as settings.CMDSET_UNLOGGEDIN
normal - gathers command sets from many different sources (shown in dropping priority):
4) Cmdsets are gathered from different sources (in order of dropping priority):
channels - all available channel names are auto-created into a cmdset, to allow
for giving the channel name and have the following immediately
sent to the channel. The sending is performed by the CMD_CHANNEL
@ -52,11 +50,17 @@ COMMAND_PARSER = utils.mod_import(*settings.COMMAND_PARSER.rsplit('.', 1))
# allow for custom behaviour when the command handler hits
# special situations -- it then calls a normal Command
# that you can customize!
# Import these variables and use them rather than trying
# to remember the actual string constants.
CMD_NOINPUT = "__noinput_command"
CMD_NOMATCH = "__nomatch_command"
CMD_MULTIMATCH = "__multimatch_command"
CMD_CHANNEL = "__send_to_channel"
CMD_CHANNEL = "__send_to_channel_command"
# this is the name of the command the engine calls when the player
# connects. It is expected to show the login screen.
CMD_LOGINSTART = "__unloggedin_look_command"
class NoCmdSets(Exception):
"No cmdsets found. Critical error."
@ -115,13 +119,14 @@ def get_and_merge_cmdsets(caller):
try:
player_cmdset = caller.player.cmdset.current
except AttributeError:
player_cmdset = None
player_cmdset = None
cmdsets = [caller_cmdset] + [player_cmdset] + [channel_cmdset] + local_objects_cmdsets
# weed out all non-found sets
cmdsets = [cmdset for cmdset in cmdsets if cmdset]
# sort cmdsets after reverse priority (highest prio are merged in last)
cmdsets = sorted(cmdsets, key=lambda x: x.priority)
if cmdsets:
# Merge all command sets into one, beginning with the lowest-prio one
cmdset = cmdsets.pop(0)
@ -131,7 +136,7 @@ def get_and_merge_cmdsets(caller):
cmdset = merging_cmdset + cmdset
else:
cmdset = None
for cset in (cset for cset in local_objects_cmdsets if cset):
cset.duplicates = cset.old_duplicates
@ -140,27 +145,21 @@ def get_and_merge_cmdsets(caller):
# Main command-handler function
def cmdhandler(caller, raw_string, unloggedin=False, testing=False):
def cmdhandler(caller, raw_string, testing=False):
"""
This is the main function to handle any string sent to the engine.
caller - calling object
raw_string - the command string given on the command line
unloggedin - if caller is an authenticated user or not
testing - if we should actually execute the command or not.
if True, the command instance will be returned instead.
"""
try: # catch bugs in cmdhandler itself
try: # catch special-type commands
if unloggedin:
# not logged in, so it's just one cmdset we are interested in
cmdset = import_cmdset(settings.CMDSET_UNLOGGEDIN, caller)
else:
# We are logged in, collect all relevant cmdsets and merge
cmdset = get_and_merge_cmdsets(caller)
cmdset = get_and_merge_cmdsets(caller)
#print cmdset
# print cmdset
if not cmdset:
# this is bad and shouldn't happen.
raise NoCmdSets
@ -171,12 +170,10 @@ def cmdhandler(caller, raw_string, unloggedin=False, testing=False):
syscmd = cmdset.get(CMD_NOINPUT)
sysarg = ""
raise ExecSystemCommand(syscmd, sysarg)
# Parse the input string and match to available cmdset.
# This also checks for permissions, so all commands in match
# are commands the caller is allowed to call.
matches = COMMAND_PARSER(raw_string, cmdset, caller)
# Deal with matches
if not matches:
# No commands match our entered command

View file

@ -49,7 +49,6 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
matches.extend([create_match(cmdname, raw_string, cmd)
for cmdname in [cmd.key] + cmd.aliases
if cmdname and l_raw_string.startswith(cmdname.lower())])
if not matches:
# no matches found.
if '-' in raw_string:

View file

@ -221,7 +221,7 @@ class CmdSet(object):
are made, rather later added commands will simply replace
existing ones to make a unique set.
"""
if inherits_from(cmd, "src.commands.cmdset.CmdSet"):
# this is a command set so merge all commands in that set
# to this one. We are not protecting against recursive
@ -235,19 +235,19 @@ class CmdSet(object):
string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain."
raise RuntimeError(string % (cmd, self.__class__))
cmds = cmd.commands
elif not is_iter(cmd):
cmds = [instantiate(cmd)]
elif is_iter(cmd):
cmds = [instantiate(c) for c in cmd]
else:
cmds = instantiate(cmd)
cmds = [instantiate(cmd)]
for cmd in cmds:
# add all commands
if not hasattr(cmd, 'obj'):
cmd.obj = self.cmdsetobj
cmd.obj = self.cmdsetobj
try:
ic = self.commands.index(cmd)
self.commands[ic] = cmd # replace
except ValueError:
self.commands.append(cmd)
self.commands.append(cmd)
# extra run to make sure to avoid doublets
self.commands = list(set(self.commands))
#print "In cmdset.add(cmd):", self.key, cmd

View file

@ -121,7 +121,8 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
logger.log_trace()
if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"):
object.__getattribute__(emit_to_obj, "msg")(errstring)
#raise # have to raise, or we will not see any errors in some situations!
logger.log_errmsg("Error: %s" % errstring)
raise # have to raise, or we will not see any errors in some situations!
# classes
@ -246,8 +247,8 @@ class CmdSetHandler(object):
def add(self, cmdset, emit_to_obj=None, permanent=False):
"""
Add a cmdset to the handler, on top of the old ones.
Default is to not make this permanent (i.e. no script
will be added to add the cmdset every server start/login).
Default is to not make this permanent, i.e. the set
will not survive a server reset.
cmdset - can be a cmdset object or the python path to
such an object.

View file

@ -129,7 +129,7 @@ class Command(object):
previously extracted from the raw string by the system.
cmdname is always lowercase when reaching this point.
"""
return (cmdname == self.key) or (cmdname in self.aliases)
return cmdname and ((cmdname == self.key) or (cmdname in self.aliases))
def access(self, srcobj, access_type="cmd", default=False):
"""

View file

@ -616,7 +616,7 @@ class CmdOOCLook(CmdLook):
self.character = None
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
# An object of some type is calling. Convert to player.
print self.caller, self.caller.__class__
#print self.caller, self.caller.__class__
self.character = self.caller
if hasattr(self.caller, "player"):
self.caller = self.caller.player
@ -685,6 +685,15 @@ class CmdIC(MuxCommand):
if caller.swap_character(new_character):
new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name)
caller.db.last_puppet = old_char
if not new_character.location:
# this might be due to being hidden away at logout; check
loc = new_character.db.prelogout_location
if not loc: # still no location; use home
loc = new_character.home
new_character.location = loc
if new_character.location:
new_character.location.msg_contents("%s has entered the game." % new_character.key, exclude=[new_character])
new_character.location.at_object_receive(new_character, new_character.location)
new_character.execute_cmd("look")
else:
caller.msg("{rYou cannot become {C%s{n." % new_character.name)
@ -720,11 +729,15 @@ class CmdOOC(MuxCommand):
return
caller.db.last_puppet = caller.character
# save location as if we were disconnecting from the game entirely.
if caller.character.location:
caller.character.location.msg_contents("%s has left the game." % caller.character.key, exclude=[caller.character])
caller.character.db.prelogout_location = caller.character.location
caller.character.location = None
# disconnect
caller.character.player = None
caller.character = None
caller.msg("\n{GYou go OOC.{n\n")
caller.execute_cmd("look")

View file

@ -13,6 +13,7 @@ from src.comms.models import Channel
from src.utils import create, logger, utils, ansi
from src.commands.default.muxcommand import MuxCommand
from src.commands.cmdhandler import CMD_LOGINSTART
CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
@ -169,20 +170,10 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m
session.msg("There was an error creating the default Character/Player. This error was logged. Contact an admin.")
return
new_player = new_character.player
# character safety features
new_character.locks.delete("get")
new_character.locks.add("get:perm(Wizards)")
# allow the character itself and the player to puppet this character.
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
(new_character.id, new_player.id))
# set a default description
new_character.db.desc = "This is a Player."
new_character.db.FIRST_LOGIN = True
new_player = new_character.player
new_player.db.FIRST_LOGIN = True
# This needs to be called so the engine knows this player is logging in for the first time.
# (so it knows to call the right hooks during login later)
utils.init_new_player(new_player)
# join the new player to the public channel
pchanneldef = settings.CHANNEL_PUBLIC
@ -191,10 +182,20 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m
if not pchannel.connect_to(new_player):
string = "New player '%s' could not connect to public channel!" % new_player.key
logger.log_errmsg(string)
# allow only the character itself and the player to puppet this character (and Immortals).
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
(new_character.id, new_player.id))
# set a default description
new_character.db.desc = "This is a Player."
# tell the caller everything went well.
string = "A new account '%s' was created with the email address %s. Welcome!"
string += "\n\nYou can now log with the command 'connect %s <your password>'."
session.msg(string % (playername, email, email))
except Exception:
# We are in the middle between logged in and -not, so we have to handle tracebacks
# ourselves at this point. If we don't, we won't see any errors at all.
@ -221,10 +222,12 @@ class CmdQuit(MuxCommand):
class CmdUnconnectedLook(MuxCommand):
"""
This is an unconnected version of the look command for simplicity.
All it does is re-show the connect screen.
This is called by the server and kicks everything in gear.
All it does is display the connect screen.
"""
key = "look"
aliases = "l"
key = CMD_LOGINSTART
aliases = ["look", "l"]
locks = "cmd:all()"
def func(self):

View file

@ -68,6 +68,13 @@ class ObjectManager(TypedObjectManager):
# use the id to find the player
return self.get_object_with_user(dbref)
@returns_typeclass_list
def get_objs_with_key_and_typeclass(self, oname, otypeclass_path):
"""
Returns objects based on simultaneous key and typeclass match.
"""
return self.filter(db_key__iexact=oname).filter(db_typeclass_path__exact=otypeclass_path)
# attr/property related
@returns_typeclass_list

View file

@ -316,7 +316,7 @@ class ObjectDB(TypedObject):
string += "%s is not a valid home."
self.msg(string % home)
logger.log_trace(string)
raise
#raise
self.save()
#@home.deleter
def home_del(self):

View file

@ -409,6 +409,34 @@ class Character(Object):
def at_after_move(self, source_location):
"Default is to look around after a move."
self.execute_cmd('look')
def at_disconnect(self):
"""
We stove away the character when logging off, otherwise the character object will
remain in the room also after the player logged off ("headless", so to say).
"""
if self.location: # have to check, in case of multiple connections closing
self.location.msg_contents("%s has left the game." % self.name, exclude=[self])
self.db.prelogout_location = self.location
self.location = None
def at_post_login(self):
"""
This recovers the character again after having been "stoved away" at disconnect.
"""
if self.db.prelogout_location:
# try to recover
self.location = self.db.prelogout_location
if self.location == None:
# make sure location is never None (home should always exist)
self.location = self.home
# save location again to be sure
self.db.prelogout_location = self.location
self.location.msg_contents("%s has entered the game." % self.name, exclude=[self])
self.location.at_object_receive(self, self.location)
#
# Base Room object

View file

@ -34,10 +34,6 @@ SERVER_RESTART = os.path.join(settings.GAME_DIR, "server.restart")
# i18n
from django.utils.translation import ugettext as _
# Signals
def get_restart_mode(restart_file):
"""
@ -141,6 +137,24 @@ class MsgServer2Portal(amp.Command):
errors = [(Exception, 'EXCEPTION')]
response = []
class OOBPortal2Server(amp.Command):
"""
OOB data portal -> server
"""
arguments = [('sessid', amp.Integer()),
('data', amp.String())]
errors = [(Exception, "EXCEPTION")]
response = []
class OOBServer2Portal(amp.Command):
"""
OOB data server -> portal
"""
arguments = [('sessid', amp.Integer()),
('data', amp.String())]
errors = [(Exception, "EXCEPTION")]
response = []
class ServerAdmin(amp.Command):
"""
Portal -> Server
@ -168,6 +182,8 @@ class PortalAdmin(amp.Command):
errors = [(Exception, 'EXCEPTION')]
response = []
dumps = lambda data: utils.to_str(pickle.dumps(data, pickle.HIGHEST_PROTOCOL))
loads = lambda data: pickle.loads(utils.to_str(data))
#------------------------------------------------------------
# Core AMP protocol for communication Server <-> Portal
@ -220,7 +236,7 @@ class AMPProtocol(amp.AMP):
Relays message to server. This method is executed on the Server.
"""
#print "msg portal -> server (server side):", sessid, msg
self.factory.server.sessions.data_in(sessid, msg, pickle.loads(utils.to_str(data)))
self.factory.server.sessions.data_in(sessid, msg, loads(data))
return {}
MsgPortal2Server.responder(amp_msg_portal2server)
@ -232,7 +248,7 @@ class AMPProtocol(amp.AMP):
self.callRemote(MsgPortal2Server,
sessid=sessid,
msg=msg,
data=utils.to_str(pickle.dumps(data))).addErrback(self.errback, "MsgPortal2Server")
data=dumps(data)).addErrback(self.errback, "MsgPortal2Server")
# Server -> Portal message
@ -241,7 +257,7 @@ class AMPProtocol(amp.AMP):
Relays message to Portal. This method is executed on the Portal.
"""
#print "msg server->portal (portal side):", sessid, msg
self.factory.portal.sessions.data_out(sessid, msg, pickle.loads(utils.to_str(data)))
self.factory.portal.sessions.data_out(sessid, msg, loads(data))
return {}
MsgServer2Portal.responder(amp_msg_server2portal)
@ -253,8 +269,50 @@ class AMPProtocol(amp.AMP):
self.callRemote(MsgServer2Portal,
sessid=sessid,
msg=utils.to_str(msg),
data=utils.to_str(pickle.dumps(data))).addErrback(self.errback, "MsgServer2Portal")
data=dumps(data)).addErrback(self.errback, "OOBServer2Portal")
# OOB Portal -> Server
# Portal -> Server Msg
def amp_oob_portal2server(self, sessid, data):
"""
Relays out-of-band data to server. This method is executed on the Server.
"""
#print "oob portal -> server (server side):", sessid, loads(data)
self.factory.server.sessions.oob_data_in(sessid, loads(data))
return {}
OOBPortal2Server.responder(amp_oob_portal2server)
def call_remote_OOBPortal2Server(self, sessid, data=""):
"""
Access method called by the Portal and executed on the Portal.
"""
#print "oob portal->server (portal side):", sessid, data
self.callRemote(OOBPortal2Server,
sessid=sessid,
data=dumps(data)).addErrback(self.errback, "OOBPortal2Server")
# Server -> Portal message
def amp_oob_server2portal(self, sessid, data):
"""
Relays out-of-band data to Portal. This method is executed on the Portal.
"""
#print "oob server->portal (portal side):", sessid, data
self.factory.portal.sessions.oob_data_out(sessid, loads(data))
return {}
OOBServer2Portal.responder(amp_oob_server2portal)
def call_remote_OOBServer2Portal(self, sessid, data=""):
"""
Access method called by the Server and executed on the Server.
"""
#print "oob server->portal (server side):", sessid, data
self.callRemote(OOBServer2Portal,
sessid=sessid,
data=dumps(data)).addErrback(self.errback, "OOBServer2Portal")
# Server administration from the Portal side
@ -264,7 +322,7 @@ class AMPProtocol(amp.AMP):
operations on the server. This is executed on the Server.
"""
data = pickle.loads(utils.to_str(data))
data = loads(data)
#print "serveradmin (server side):", sessid, operation, data
@ -276,7 +334,7 @@ class AMPProtocol(amp.AMP):
if sess.logged_in and sess.uid:
# this can happen in the case of auto-authenticating protocols like SSH
sess.player = PlayerDB.objects.get_player_from_uid(sess.uid)
sess.at_sync() # this runs initialization without acr
sess.at_sync() # this runs initialization without acr
self.factory.server.sessions.portal_connect(sessid, sess)
@ -315,7 +373,7 @@ class AMPProtocol(amp.AMP):
Access method called by the Portal and Executed on the Portal.
"""
#print "serveradmin (portal side):", sessid, operation, data
data = utils.to_str(pickle.dumps(data))
data = dumps(data)
self.callRemote(ServerAdmin,
sessid=sessid,
@ -329,7 +387,7 @@ class AMPProtocol(amp.AMP):
This allows the server to perform admin
operations on the portal. This is executed on the Portal.
"""
data = pickle.loads(utils.to_str(data))
data = loads(data)
#print "portaladmin (portal side):", sessid, operation, data
if operation == 'SLOGIN': # 'server_session_login'
@ -376,7 +434,7 @@ class AMPProtocol(amp.AMP):
Access method called by the server side.
"""
#print "portaladmin (server side):", sessid, operation, data
data = utils.to_str(pickle.dumps(data))
data = dumps(data)
self.callRemote(PortalAdmin,
sessid=sessid,

View file

@ -59,8 +59,7 @@ def create_objects():
character_typeclass=character_typeclass)
if not god_character:
print _("#1 could not be created. Check the Player/Character typeclass for bugs.")
raise Exception
raise Exception(_("#1 could not be created. Check the Player/Character typeclass for bugs."))
god_character.id = 1
god_character.db.desc = _('This is User #1.')

View file

@ -12,12 +12,16 @@ from datetime import datetime
from django.conf import settings
from src.scripts.models import ScriptDB
from src.comms.models import Channel
from src.utils import logger
from src.commands import cmdhandler
from src.utils import logger, utils
from src.commands import cmdhandler, cmdsethandler
from src.server.session import Session
IDLE_COMMAND = settings.IDLE_COMMAND
from src.server.session import Session
# load optional out-of-band function module
OOB_FUNC_MODULE = settings.OOB_FUNC_MODULE
if OOB_FUNC_MODULE:
OOB_FUNC_MODULE = utils.mod_import(settings.OOB_FUNC_MODULE)
# i18n
from django.utils.translation import ugettext as _
@ -37,7 +41,6 @@ class ServerSession(Session):
through their session.
"""
def at_sync(self):
"""
This is called whenever a session has been resynced with the portal.
@ -48,12 +51,18 @@ class ServerSession(Session):
the session as it was.
"""
if not self.logged_in:
# assign the unloggedin-command set.
self.cmdset = cmdsethandler.CmdSetHandler(self)
self.cmdset_storage = [settings.CMDSET_UNLOGGEDIN]
self.cmdset.update(init_mode=True)
self.cmdset.update(init_mode=True)
return
character = self.get_character()
if character:
# start (persistent) scripts on this object
ScriptDB.objects.validate(obj=character)
def session_login(self, player):
"""
Startup mechanisms that need to run at login. This is called
@ -87,11 +96,10 @@ class ServerSession(Session):
player.at_pre_login()
character = player.character
#print "at_init() - character"
character.at_init()
if character:
# this player has a character. Check if it's the
# first time *this character* logs in
character.at_init()
if character.db.FIRST_LOGIN:
character.at_first_login()
del character.db.FIRST_LOGIN
@ -181,7 +189,7 @@ class ServerSession(Session):
if str(command_string).strip() == IDLE_COMMAND:
self.update_session_counters(idle=True)
return
# all other inputs, including empty inputs
character = self.get_character()
@ -193,8 +201,9 @@ class ServerSession(Session):
# there is no character, but we are logged in. Use player instead.
self.get_player().execute_cmd(command_string)
else:
# we are not logged in. Use special unlogged-in call.
cmdhandler.cmdhandler(self, command_string, unloggedin=True)
# we are not logged in. Use the session directly
# (it uses the settings.UNLOGGEDIN cmdset)
cmdhandler.cmdhandler(self, command_string)
self.update_session_counters()
def data_out(self, msg, data=None):
@ -203,9 +212,57 @@ class ServerSession(Session):
"""
self.sessionhandler.data_out(self, msg, data)
def oob_data_in(self, data):
"""
This receives out-of-band data from the Portal.
This method parses the data input (a dict) and uses
it to launch correct methods from those plugged into
the system.
data = {funcname: ( [args], {kwargs]),
funcname: ( [args], {kwargs}), ...}
example:
data = {"get_hp": ([], {}),
"update_counter", (["counter1"], {"now":True}) }
"""
print "server: "
outdata = {}
entity = self.get_character()
if not entity:
entity = self.get_player()
if not entity:
entity = self
for funcname, argtuple in data.items():
# loop through the data, calling available functions.
func = OOB_FUNC_MODULE.__dict__.get(funcname, None)
if func:
try:
outdata[funcname] = func(entity, *argtuple[0], **argtuple[1])
except Exception:
logger.log_trace()
else:
logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % funcname)
if outdata:
self.oob_data_out(outdata)
def oob_data_out(self, data):
"""
This sends data from Server to the Portal across the AMP connection.
"""
self.sessionhandler.oob_data_out(self, data)
def __eq__(self, other):
return self.address == other.address
def __str__(self):
"""
String representation of the user session class. We use
@ -239,3 +296,57 @@ class ServerSession(Session):
def msg(self, string='', data=None):
"alias for at_data_out"
self.data_out(string, data=data)
# Dummy API hooks for use a non-loggedin operation
def at_cmdset_get(self):
"dummy hook all objects with cmdsets need to have"
pass
# Mock db/ndb properties for allowing easy storage on the session
# (note that no databse is involved at all here. session.db.attr =
# value just saves a normal property in memory, just like ndb).
#@property
def ndb_get(self):
"""
A non-persistent store (ndb: NonDataBase). Everything stored
to this is guaranteed to be cleared when a server is shutdown.
Syntax is same as for the _get_db_holder() method and
property, e.g. obj.ndb.attr = value etc.
"""
try:
return self._ndb_holder
except AttributeError:
class NdbHolder(object):
"Holder for storing non-persistent attributes."
def all(self):
return [val for val in self.__dict__.keys()
if not val.startswith['_']]
def __getattribute__(self, key):
# return None if no matching attribute was found.
try:
return object.__getattribute__(self, key)
except AttributeError:
return None
self._ndb_holder = NdbHolder()
return self._ndb_holder
#@ndb.setter
def ndb_set(self, value):
"Stop accidentally replacing the db object"
string = "Cannot assign directly to ndb object! "
string = "Use ndb.attr=value instead."
raise Exception(string)
#@ndb.deleter
def ndb_del(self):
"Stop accidental deletion."
raise Exception("Cannot delete the ndb object!")
ndb = property(ndb_get, ndb_set, ndb_del)
db = property(ndb_get, ndb_set, ndb_del)
# Mock access method for the session (there is no lock info
# at this stage, so we just present a uniform API)
def access(self, *args, **kwargs):
"Dummy method."
return True

View file

@ -123,3 +123,20 @@ class Session(object):
"""
pass
def oob_data_out(self, data):
"""
for Portal, this receives out-of-band data from Server across the AMP.
for Server, this sends out-of-band data to Portal.
data is a dictionary
"""
pass
def oob_data_in(self, data):
"""
for Portal, this sends out-of-band requests to Server over the AMP.
for Server, this receives data from Portal.
data is a dictionary
"""
pass

View file

@ -19,6 +19,8 @@ from django.contrib.auth.models import User
from src.server.models import ServerConfig
from src.utils import utils
from src.commands.cmdhandler import CMD_LOGINSTART
# i18n
from django.utils.translation import ugettext as _
@ -94,7 +96,7 @@ class ServerSessionHandler(SessionHandler):
Creates a new, unlogged-in game session.
"""
self.sessions[sessid] = session
session.execute_cmd('look')
session.execute_cmd(CMD_LOGINSTART)
def portal_disconnect(self, sessid):
"""
@ -293,6 +295,20 @@ class ServerSessionHandler(SessionHandler):
# to put custom effects on the server due to data input, e.g.
# from a custom client.
def oob_data_in(self, sessid, data):
"""
OOB (Out-of-band) Data Portal -> Server
"""
session = self.sessions.get(sessid, None)
if session:
session.oob_data_in(data)
def oob_data_out(self, session, data):
"""
OOB (Out-of-band) Data Server -> Portal
"""
self.server.amp_protocol.call_remote_OOBServer2Portal(session.sessid,
data=data)
#------------------------------------------------------------
# Portal-SessionHandler class
@ -390,5 +406,20 @@ class PortalSessionHandler(SessionHandler):
if session:
session.data_out(string, data=data)
def oob_data_in(self, session, data):
"""
OOB (Out-of-band) data Portal -> Server
"""
self.portal.amp_protocol.call_remote_OOBPortal2Server(session.sessid,
data=data)
def oob_data_out(self, sessid, data):
"""
OOB (Out-of-band) data Server -> Portal
"""
session = self.sessions.get(sessid, None)
if session:
session.oob_data_out(data)
SESSIONS = ServerSessionHandler()
PORTAL_SESSIONS = PortalSessionHandler()

View file

@ -167,6 +167,12 @@ AT_INITIAL_SETUP_HOOK_MODULE = "game.gamesrc.world.at_initial_setup"
###################################################
# Default command sets
###################################################
# Note that with the exception of the unloggedin set (which is not
# stored anywhere), changing these paths will only affect NEW created
# characters, not those already in play. So if you plan to change
# this, it's recommended you do it on a pristine setup only. To
# dynamically add new commands to a running server, extend/overload
# these existing sets instead.
# Command set used before player has logged in
CMDSET_UNLOGGEDIN = "game.gamesrc.commands.basecmdset.UnloggedinCmdSet"
@ -246,6 +252,8 @@ PERMISSION_PLAYER_DEFAULT = "Players"
# Tuple of modules implementing lock functions. All callable functions
# inside these modules will be available as lock functions.
LOCK_FUNC_MODULES = ("src.locks.lockfuncs",)
# Module holding server-side functions for out-of-band protocols to call.
OOB_FUNC_MODULE = ""
###################################################

View file

@ -73,6 +73,7 @@ def create_object(typeclass, key=None, location=None,
# this will either load the typeclass or the default one
new_object = new_db_object.typeclass
if not object.__getattribute__(new_db_object, "is_typeclass")(typeclass, exact=True):
# this will fail if we gave a typeclass as input and it still gave us a default
SharedMemoryModel.delete(new_db_object)
@ -105,6 +106,10 @@ def create_object(typeclass, key=None, location=None,
# perform a move_to in order to display eventual messages.
if home:
new_object.home = home
else:
new_object.home = settings.CHARACTER_DEFAULT_HOME
if location:
new_object.move_to(location, quiet=True)
else:
@ -389,6 +394,8 @@ def create_player(name, email, password,
from src.players.models import PlayerDB
from src.players.player import Player
if not email:
email = "dummy@dummy.com"
if user:
new_user = user
else:

View file

@ -542,7 +542,7 @@ def has_parent(basepath, obj):
def mod_import(mod_path, propname=None):
"""
Takes filename of a module, converts it to a python path
Takes filename of a module (a python path or a full pathname)
and imports it. If property is given, return the named
property from this module instead of the module itself.
"""
@ -624,3 +624,15 @@ def string_from_module(modpath, variable=None):
if not mvars:
return None
return mvars[random.randint(0, len(mvars)-1)]
def init_new_player(player):
"""
Helper method to call all hooks, set flags etc on a newly created
player (and potentially their character, if it exists already)
"""
# the FIRST_LOGIN flags are necessary for the system to call
# the relevant first-login hooks.
if player.character:
player.character.db.FIRST_LOGIN = True
player.db.FIRST_LOGIN = True