Merge.
This commit is contained in:
commit
e345d659fd
23 changed files with 935 additions and 295 deletions
|
|
@ -41,7 +41,6 @@ from twisted.internet.defer import inlineCallbacks, returnValue
|
|||
from django.conf import settings
|
||||
from src.comms.channelhandler import CHANNELHANDLER
|
||||
from src.utils import logger, utils
|
||||
from src.commands.cmdset import CmdSet
|
||||
from src.commands.cmdparser import at_multimatch_cmd
|
||||
from src.utils.utils import string_suggestions
|
||||
|
||||
|
|
@ -165,7 +164,7 @@ def get_and_merge_cmdsets(caller):
|
|||
# Main command-handler function
|
||||
|
||||
@inlineCallbacks
|
||||
def cmdhandler(caller, raw_string, testing=False):
|
||||
def cmdhandler(caller, raw_string, testing=False, sessid=None):
|
||||
"""
|
||||
This is the main function to handle any string sent to the engine.
|
||||
|
||||
|
|
@ -251,6 +250,7 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
cmd.cmdstring = cmdname
|
||||
cmd.args = args
|
||||
cmd.cmdset = cmdset
|
||||
cmd.sessid = sessid
|
||||
cmd.raw_string = unformatted_raw_string
|
||||
|
||||
if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'):
|
||||
|
|
|
|||
|
|
@ -1701,13 +1701,16 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
if not self.args:
|
||||
# If no arguments are provided, examine the invoker's location.
|
||||
obj = caller.location
|
||||
if not obj.access(caller, 'examine'):
|
||||
#If we don't have special info access, just look at the object instead.
|
||||
caller.execute_cmd('look %s' % obj.name)
|
||||
return
|
||||
# using callback for printing result whenever function returns.
|
||||
get_and_merge_cmdsets(obj).addCallback(get_cmdset_callback)
|
||||
if hasattr(caller, "location"):
|
||||
obj = caller.location
|
||||
if not obj.access(caller, 'examine'):
|
||||
#If we don't have special info access, just look at the object instead.
|
||||
caller.execute_cmd('look %s' % obj.name)
|
||||
return
|
||||
# using callback for printing result whenever function returns.
|
||||
get_and_merge_cmdsets(obj).addCallback(get_cmdset_callback)
|
||||
else:
|
||||
caller.msg("You need to supply a target to examine.")
|
||||
return
|
||||
|
||||
# we have given a specific target object
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ a Player object as caller rather than a Character.
|
|||
from src.commands.cmdset import CmdSet
|
||||
from src.commands.default import help, comms, general, admin, system
|
||||
|
||||
from src.commands.default import building
|
||||
class OOCCmdSet(CmdSet):
|
||||
"""
|
||||
Implements the player command set.
|
||||
|
|
@ -23,10 +24,14 @@ class OOCCmdSet(CmdSet):
|
|||
self.add(general.CmdOOCLook())
|
||||
self.add(general.CmdIC())
|
||||
self.add(general.CmdOOC())
|
||||
self.add(general.CmdCharCreate())
|
||||
self.add(general.CmdEncoding())
|
||||
self.add(general.CmdQuit())
|
||||
self.add(general.CmdPassword())
|
||||
|
||||
# test
|
||||
self.add(building.CmdExamine())
|
||||
|
||||
# Help command
|
||||
self.add(help.CmdHelp())
|
||||
|
||||
|
|
@ -34,6 +39,7 @@ class OOCCmdSet(CmdSet):
|
|||
self.add(system.CmdReload())
|
||||
self.add(system.CmdReset())
|
||||
self.add(system.CmdShutdown())
|
||||
self.add(system.CmdPy())
|
||||
|
||||
# Admin commands
|
||||
self.add(admin.CmdDelPlayer())
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ now.
|
|||
import time
|
||||
from django.conf import settings
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
from src.utils import utils, search
|
||||
from src.utils import utils, search, create
|
||||
from src.objects.models import ObjectNick as Nick
|
||||
from src.commands.default.muxcommand import MuxCommand, MuxCommandOOC
|
||||
|
||||
|
|
@ -573,7 +573,7 @@ class CmdEncoding(MuxCommand):
|
|||
Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc.
|
||||
|
||||
If you don't submit an encoding, the current encoding will be displayed instead.
|
||||
"""
|
||||
"""
|
||||
|
||||
key = "@encoding"
|
||||
aliases = "@encode"
|
||||
|
|
@ -649,151 +649,6 @@ class CmdAccess(MuxCommand):
|
|||
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
|
||||
caller.msg(string)
|
||||
|
||||
# OOC commands
|
||||
|
||||
class CmdOOCLook(MuxCommandOOC, CmdLook):
|
||||
"""
|
||||
ooc look
|
||||
|
||||
Usage:
|
||||
look
|
||||
|
||||
This is an OOC version of the look command. Since a
|
||||
Player doesn't have an in-game existence, there is no
|
||||
concept of location or "self". If we are controlling
|
||||
a character, pass control over to normal look.
|
||||
|
||||
"""
|
||||
|
||||
key = "look"
|
||||
aliases = ["l", "ls"]
|
||||
locks = "cmd:all()"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"implement the ooc look command"
|
||||
|
||||
if not self.character:
|
||||
string = "You are out-of-character (OOC). "
|
||||
string += "Use {w@ic{n to get back to the game, {whelp{n for more info."
|
||||
self.caller.msg(string)
|
||||
else:
|
||||
self.caller = self.character # we have to put this back for normal look to work.
|
||||
super(CmdOOCLook, self).func()
|
||||
|
||||
class CmdIC(MuxCommandOOC):
|
||||
"""
|
||||
Switch control to an object
|
||||
|
||||
Usage:
|
||||
@ic <character>
|
||||
|
||||
Go in-character (IC) as a given Character.
|
||||
|
||||
This will attempt to "become" a different object assuming you have
|
||||
the right to do so. Note that it's the PLAYER character that puppets
|
||||
characters/objects and which needs to have the correct permission!
|
||||
|
||||
You cannot become an object that is already controlled by another
|
||||
player. In principle <character> can be any in-game object as long
|
||||
as you the player have access right to puppet it.
|
||||
"""
|
||||
|
||||
key = "@ic"
|
||||
locks = "cmd:all()" # must be all() or different puppeted objects won't be able to access it.
|
||||
aliases = "@puppet"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
Simple puppet method
|
||||
"""
|
||||
caller = self.caller
|
||||
old_character = self.character
|
||||
|
||||
new_character = None
|
||||
if not self.args:
|
||||
new_character = caller.db.last_puppet
|
||||
if not new_character:
|
||||
caller.msg("Usage: @ic <character>")
|
||||
return
|
||||
if not new_character:
|
||||
# search for a matching character
|
||||
new_character = search.objects(self.args, caller)
|
||||
if new_character:
|
||||
new_character = new_character[0]
|
||||
else:
|
||||
# the search method handles error messages etc.
|
||||
return
|
||||
if new_character.player:
|
||||
if new_character.player == caller:
|
||||
caller.msg("{RYou already are {c%s{n." % new_character.name)
|
||||
else:
|
||||
caller.msg("{c%s{r is already acted by another player.{n" % new_character.name)
|
||||
return
|
||||
if not new_character.access(caller, "puppet"):
|
||||
caller.msg("{rYou may not become %s.{n" % new_character.name)
|
||||
return
|
||||
if caller.swap_character(new_character):
|
||||
new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name)
|
||||
caller.db.last_puppet = old_character
|
||||
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)
|
||||
|
||||
class CmdOOC(MuxCommandOOC):
|
||||
"""
|
||||
@ooc - go ooc
|
||||
|
||||
Usage:
|
||||
@ooc
|
||||
|
||||
Go out-of-character (OOC).
|
||||
|
||||
This will leave your current character and put you in a incorporeal OOC state.
|
||||
"""
|
||||
|
||||
key = "@ooc"
|
||||
locks = "cmd:all()" # this must be all(), or different puppeted objects won't be able to access it.
|
||||
aliases = "@unpuppet"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"Implement function"
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if utils.inherits_from(caller, "src.objects.objects.Object"):
|
||||
caller = self.caller.player
|
||||
|
||||
if not caller.character:
|
||||
string = "You are already OOC."
|
||||
caller.msg(string)
|
||||
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")
|
||||
|
||||
class CmdColorTest(MuxCommand):
|
||||
"""
|
||||
testing colors
|
||||
|
|
@ -851,3 +706,235 @@ class CmdColorTest(MuxCommand):
|
|||
self.caller.msg(string)
|
||||
self.caller.msg("(e.g. %%c123 and %%cb123 also work)")
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# OOC commands
|
||||
#------------------------------------------------------------
|
||||
|
||||
class CmdOOCLook(MuxCommandOOC, CmdLook):
|
||||
"""
|
||||
ooc look
|
||||
|
||||
Usage:
|
||||
look
|
||||
|
||||
Look in the ooc state.
|
||||
"""
|
||||
|
||||
#This is an OOC version of the look command. Since a
|
||||
#Player doesn't have an in-game existence, there is no
|
||||
#concept of location or "self". If we are controlling
|
||||
#a character, pass control over to normal look.
|
||||
|
||||
key = "look"
|
||||
aliases = ["l", "ls"]
|
||||
locks = "cmd:all()"
|
||||
help_category = "General"
|
||||
|
||||
def look_target(self):
|
||||
"Hook method for when an argument is given."
|
||||
# caller is assumed to be a player object here.
|
||||
caller = self.caller
|
||||
key = self.args.lower()
|
||||
chars = dict((utils.to_str(char.key.lower()), char) for char in caller.db._playable_characters)
|
||||
looktarget = chars.get(key)
|
||||
if looktarget:
|
||||
caller.msg(looktarget.return_appearance(caller))
|
||||
else:
|
||||
caller.msg("No such character.")
|
||||
return
|
||||
|
||||
def no_look_target(self):
|
||||
"Hook method for default look without a specified target"
|
||||
# caller is always a player at this point.
|
||||
player = self.caller
|
||||
sessid = self.sessid
|
||||
# get all our characters
|
||||
characters = player.db._playable_characters
|
||||
string = "You are logged in as {g%s{n." % player.key
|
||||
string += "\nUse {w@ic <character>{n to enter the game, {w@occ{n to get back here."
|
||||
if characters:
|
||||
string += "\n\nAvailable character%s:" % (len(characters) > 1 and "s" or "")
|
||||
for char in characters:
|
||||
csessid = char.sessid
|
||||
if csessid:
|
||||
# character is already puppeted
|
||||
if player.get_session(csessid):
|
||||
string += "\n - {G%s{n (played by you in another session)" % char.key
|
||||
else:
|
||||
string += "\n - {R%s{n (played by someone else)" % char.key
|
||||
else:
|
||||
# character is "free to puppet"
|
||||
string += "\n - %s" % char.key
|
||||
player.msg(string)
|
||||
|
||||
def func(self):
|
||||
"implement the ooc look command"
|
||||
|
||||
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
|
||||
# An object of some type is calling. Use default look instead.
|
||||
super(CmdOOCLook, self).func()
|
||||
elif self.args:
|
||||
self.look_target()
|
||||
else:
|
||||
self.no_look_target()
|
||||
|
||||
class CmdCharCreate(MuxCommandOOC):
|
||||
"""
|
||||
Create a character
|
||||
|
||||
Usage:
|
||||
@charcreate <charname> [= desc]
|
||||
|
||||
Create a new character, optionally giving it a description.
|
||||
"""
|
||||
key = "@charcreate"
|
||||
locks = "cmd:all()"
|
||||
help_category = "General"
|
||||
|
||||
MAX_NR_CHARACTERS = 2
|
||||
|
||||
def func(self):
|
||||
"create the new character"
|
||||
player = self.caller
|
||||
if not self.args:
|
||||
player.msg("Usage: @charcreate <charname> [= description]")
|
||||
return
|
||||
key = self.lhs
|
||||
desc = self.rhs
|
||||
if player.db._playable_characters and len(player.db._playable_characters) >= self.MAX_NR_CHARACTERS:
|
||||
player.msg("You may only create a maximum of %i characters." % self.MAX_NR_CHARACTERS)
|
||||
return
|
||||
# create the character
|
||||
from src.objects.models import ObjectDB
|
||||
|
||||
default_home = ObjectDB.objects.get_id(settings.CHARACTER_DEFAULT_HOME)
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
|
||||
new_character = create.create_object(typeclass, key=key, location=default_home,
|
||||
home=default_home, permissions=permissions)
|
||||
player.db._playable_characters.append(new_character)
|
||||
if desc:
|
||||
new_character.db.desc = desc
|
||||
player.msg("Created new character %s." % new_character.key)
|
||||
|
||||
|
||||
class CmdIC(MuxCommandOOC):
|
||||
"""
|
||||
Switch control to an object
|
||||
|
||||
Usage:
|
||||
@ic <character>
|
||||
|
||||
Go in-character (IC) as a given Character.
|
||||
|
||||
This will attempt to "become" a different object assuming you have
|
||||
the right to do so. Note that it's the PLAYER character that puppets
|
||||
characters/objects and which needs to have the correct permission!
|
||||
|
||||
You cannot become an object that is already controlled by another
|
||||
player. In principle <character> can be any in-game object as long
|
||||
as you the player have access right to puppet it.
|
||||
"""
|
||||
|
||||
key = "@ic"
|
||||
locks = "cmd:all()" # must be all() or different puppeted objects won't be able to access it.
|
||||
aliases = "@puppet"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
Simple puppet method
|
||||
"""
|
||||
caller = self.caller
|
||||
sessid = self.sessid
|
||||
old_character = self.character
|
||||
|
||||
new_character = None
|
||||
if not self.args:
|
||||
new_character = caller.db.last_puppet
|
||||
if not new_character:
|
||||
caller.msg("Usage: @ic <character>")
|
||||
return
|
||||
if not new_character:
|
||||
# search for a matching character
|
||||
new_character = search.objects(self.args, caller)
|
||||
if new_character:
|
||||
new_character = new_character[0]
|
||||
else:
|
||||
# the search method handles error messages etc.
|
||||
return
|
||||
# permission checks
|
||||
if caller.get_character(sessid=sessid, character=new_character):
|
||||
caller.msg("{RYou already act as {c%s{n." % new_character.name)
|
||||
return
|
||||
if new_character.player:
|
||||
if new_character.sessid == sessid:
|
||||
caller.msg("{RYou already act as {c%s{n from another session." % new_character.name)
|
||||
return
|
||||
elif not caller.get_character(character=new_character):
|
||||
caller.msg("{c%s{r is already acted by another player.{n" % new_character.name)
|
||||
return
|
||||
if not new_character.access(caller, "puppet"):
|
||||
caller.msg("{rYou may not become %s.{n" % new_character.name)
|
||||
return
|
||||
if caller.connect_character(new_character, sessid=sessid):
|
||||
new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name)
|
||||
caller.db.last_puppet = old_character
|
||||
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)
|
||||
|
||||
class CmdOOC(MuxCommandOOC):
|
||||
"""
|
||||
@ooc - go ooc
|
||||
|
||||
Usage:
|
||||
@ooc
|
||||
|
||||
Go out-of-character (OOC).
|
||||
|
||||
This will leave your current character and put you in a incorporeal OOC state.
|
||||
"""
|
||||
|
||||
key = "@ooc"
|
||||
locks = "cmd:all()" # this must be all(), or different puppeted objects won't be able to access it.
|
||||
aliases = "@unpuppet"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"Implement function"
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if utils.inherits_from(caller, "src.objects.objects.Object"):
|
||||
caller = self.caller.player
|
||||
|
||||
old_char = caller.get_character(sessid=self.sessid)
|
||||
if not old_char:
|
||||
string = "You are already OOC."
|
||||
caller.msg(string)
|
||||
return
|
||||
|
||||
caller.db.last_puppet = old_char
|
||||
# save location as if we were disconnecting from the game entirely.
|
||||
if old_char.location:
|
||||
old_char.location.msg_contents("%s has left the game." % old_char.key, exclude=[old_char])
|
||||
old_char.db.prelogout_location = old_char.location
|
||||
old_char.location = None
|
||||
|
||||
# disconnect
|
||||
err = caller.disconnect_character(self.character)
|
||||
caller.msg("\n{GYou go OOC.{n\n")
|
||||
caller.execute_cmd("look")
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,6 @@ class MuxCommandOOC(MuxCommand):
|
|||
self.caller = self.caller.player
|
||||
elif hasattr(self.caller, "character"):
|
||||
# caller was already a Player
|
||||
self.character = self.caller.character
|
||||
self.character = self.caller.get_character(sessid=self.sessid)
|
||||
else:
|
||||
self.character = None
|
||||
|
|
|
|||
|
|
@ -146,15 +146,17 @@ class CmdPy(MuxCommand):
|
|||
caller.msg(string)
|
||||
return
|
||||
|
||||
# check if caller is a player
|
||||
|
||||
# import useful variables
|
||||
import ev
|
||||
available_vars = {'self':caller,
|
||||
'me':caller,
|
||||
'here':caller.location,
|
||||
'here':hasattr(caller, "location") and caller.location or None,
|
||||
'ev':ev,
|
||||
'inherits_from':utils.inherits_from}
|
||||
|
||||
caller.msg(">>> %s" % pycode, data={"raw":True})
|
||||
caller.msg(">>> %s" % pycode, data={"raw":True}, sessid=self.sessid)
|
||||
|
||||
mode = "eval"
|
||||
try:
|
||||
|
|
@ -183,7 +185,7 @@ class CmdPy(MuxCommand):
|
|||
ret = "\n".join("{n<<< %s" % line for line in errlist if line)
|
||||
|
||||
if ret != None:
|
||||
caller.msg(ret)
|
||||
caller.msg(ret, sessid=self.sessid)
|
||||
|
||||
# helper function. Kept outside so it can be imported and run
|
||||
# by other commands.
|
||||
|
|
|
|||
|
|
@ -161,15 +161,19 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
|
||||
try:
|
||||
new_character = create.create_player(playername, None, password,
|
||||
permissions=permissions,
|
||||
character_typeclass=typeclass,
|
||||
character_location=default_home,
|
||||
character_home=default_home)
|
||||
new_player = create.create_player(playername, None, password,
|
||||
permissions=permissions)
|
||||
|
||||
# create character to go with player
|
||||
new_character = create_object(character_typeclass, key=name,
|
||||
location=default_home, home=default_home,
|
||||
permissions=permissions)
|
||||
# set list
|
||||
new_player.db._playable_characters.append(new_character)
|
||||
|
||||
except Exception:
|
||||
session.msg("There was an error creating the default Character/Player:\n%s\n If this problem persists, contact an admin.")
|
||||
session.msg("There was an error creating the default Player/Character:\n%s\n If this problem persists, contact an admin.")
|
||||
return
|
||||
new_player = new_character.player
|
||||
|
||||
# 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)
|
||||
|
|
|
|||
|
|
@ -365,3 +365,12 @@ class ObjectManager(TypedObjectManager):
|
|||
ScriptDB.objects.copy_script(script, new_obj=new_object.dbobj)
|
||||
|
||||
return new_object
|
||||
|
||||
|
||||
def clear_all_sessids(self):
|
||||
"""
|
||||
Clear the db_sessid field of all objects having also the db_player field
|
||||
set.
|
||||
"""
|
||||
self.filter(db_sessid__isnull=False).update(db_sessid=None)
|
||||
|
||||
|
|
|
|||
113
src/objects/migrations/0016_adding_sessid.py
Normal file
113
src/objects/migrations/0016_adding_sessid.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'ObjectDB.db_sessid'
|
||||
db.add_column('objects_objectdb', 'db_sessid',
|
||||
self.gf('django.db.models.fields.IntegerField')(null=True),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'ObjectDB.db_sessid'
|
||||
db.delete_column('objects_objectdb', 'db_sessid')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'objects.alias': {
|
||||
'Meta': {'object_name': 'Alias'},
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'objects.objattribute': {
|
||||
'Meta': {'object_name': 'ObjAttribute'},
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'objects.objectdb': {
|
||||
'Meta': {'object_name': 'ObjectDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||
'db_sessid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'objects.objectnick': {
|
||||
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'},
|
||||
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'players.playerdb': {
|
||||
'Meta': {'object_name': 'PlayerDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'obj_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_objs': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'objs_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['objects']
|
||||
|
|
@ -21,7 +21,7 @@ from django.conf import settings
|
|||
from src.utils.idmapper.models import SharedMemoryModel
|
||||
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache, hashid
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
from src.players.models import PlayerNick
|
||||
from src.objects.manager import ObjectManager
|
||||
|
|
@ -176,6 +176,9 @@ class ObjectDB(TypedObject):
|
|||
# If this is a character object, the player is connected here.
|
||||
db_player = models.ForeignKey("players.PlayerDB", blank=True, null=True, verbose_name='player',
|
||||
help_text='a Player connected to this object, if any.')
|
||||
# the session id associated with this player, if any
|
||||
db_sessid = models.IntegerField(null=True, verbose_name="session id",
|
||||
help_text="unique session id of connected Player, if any.")
|
||||
# The location in the game world. Since this one is likely
|
||||
# to change often, we set this with the 'location' property
|
||||
# to transparently handle Typeclassing.
|
||||
|
|
@ -191,7 +194,6 @@ class ObjectDB(TypedObject):
|
|||
# database storage of persistant cmdsets.
|
||||
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True, blank=True,
|
||||
help_text="optional python path to a cmdset class.")
|
||||
|
||||
# Database manager
|
||||
objects = ObjectManager()
|
||||
|
||||
|
|
@ -260,6 +262,28 @@ class ObjectDB(TypedObject):
|
|||
del_field_cache(self, "player")
|
||||
player = property(__player_get, __player_set, __player_del)
|
||||
|
||||
# sessid property (wraps db_sessid)
|
||||
#@property
|
||||
def __sessid_get(self):
|
||||
"""
|
||||
Getter. Allows for value = self.sessid. Since sessid
|
||||
is directly related to self.player, we cannot have
|
||||
a sessid without a player being connected (but the
|
||||
opposite could be true).
|
||||
"""
|
||||
if not get_field_cache(self, "sessid"):
|
||||
del_field_cache(self, "sessid")
|
||||
return get_field_cache(self, "sessid")
|
||||
#@sessid.setter
|
||||
def __sessid_set(self, sessid):
|
||||
"Setter. Allows for self.player = value"
|
||||
set_field_cache(self, "sessid", sessid)
|
||||
#@sessid.deleter
|
||||
def __sessid_del(self):
|
||||
"Deleter. Allows for del self.player"
|
||||
del_field_cache(self, "sessid")
|
||||
sessid = property(__sessid_get, __sessid_set, __sessid_del)
|
||||
|
||||
# location property (wraps db_location)
|
||||
#@property
|
||||
def __location_get(self):
|
||||
|
|
@ -612,7 +636,7 @@ class ObjectDB(TypedObject):
|
|||
# Execution/action methods
|
||||
#
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
|
|
@ -644,11 +668,11 @@ class ObjectDB(TypedObject):
|
|||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string)
|
||||
return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, sessid=sessid)
|
||||
|
||||
def msg(self, message, from_obj=None, data=None):
|
||||
"""
|
||||
Emits something to any sessions attached to the object.
|
||||
Emits something to a session attached to the object.
|
||||
|
||||
message (str): The message to send
|
||||
from_obj (obj): object that is sending.
|
||||
|
|
@ -656,8 +680,8 @@ class ObjectDB(TypedObject):
|
|||
be used by the protocol.
|
||||
"""
|
||||
if _GA(self, 'player'):
|
||||
# note that we check the typeclass' msg, otherwise one couldn't overload it.
|
||||
_GA(_GA(self, 'player'), "typeclass").msg(message, from_obj=from_obj, data=data)
|
||||
# note that we must call the player *typeclass'* msg(), otherwise one couldn't overload it.
|
||||
_GA(_GA(self, 'player'), "typeclass").msg(message, from_obj=from_obj, data=data, sessid=_GA(self, "sessid"))
|
||||
|
||||
def emit_to(self, message, from_obj=None, data=None):
|
||||
"Deprecated. Alias for msg"
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class Object(TypeClass):
|
|||
ignore_errors=ignore_errors,
|
||||
player=player)
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
|
|
@ -209,6 +209,7 @@ class Object(TypeClass):
|
|||
|
||||
Argument:
|
||||
raw_string (string) - raw command input
|
||||
sessid (int) - id of session executing the command. This sets the sessid property on the command.
|
||||
|
||||
Returns Deferred - this is an asynchronous Twisted object that will
|
||||
not fire until the command has actually finished executing. To overload
|
||||
|
|
@ -219,7 +220,7 @@ class Object(TypeClass):
|
|||
This return is not used at all by Evennia by default, but might be useful
|
||||
for coders intending to implement some sort of nested command structure.
|
||||
"""
|
||||
return self.dbobj.execute_cmd(raw_string)
|
||||
return self.dbobj.execute_cmd(raw_string, sessid=sessid)
|
||||
|
||||
def msg(self, message, from_obj=None, data=None):
|
||||
"""
|
||||
|
|
|
|||
116
src/players/migrations/0014_adding_objs_m2m.py
Normal file
116
src/players/migrations/0014_adding_objs_m2m.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding M2M table for field db_objs on 'PlayerDB'
|
||||
db.create_table('players_playerdb_db_objs', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('playerdb', models.ForeignKey(orm['players.playerdb'], null=False)),
|
||||
('objectdb', models.ForeignKey(orm['objects.objectdb'], null=False))
|
||||
))
|
||||
db.create_unique('players_playerdb_db_objs', ['playerdb_id', 'objectdb_id'])
|
||||
|
||||
if not db.dry_run:
|
||||
for player in orm.PlayerDB.objects.all():
|
||||
# move data from old field to new
|
||||
if player.db_obj:
|
||||
player.db_objs.add(player.db_obj)
|
||||
player.save()
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing M2M table for field db_objs on 'PlayerDB'
|
||||
db.delete_table('players_playerdb_db_objs')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'objects.objectdb': {
|
||||
'Meta': {'object_name': 'ObjectDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||
'db_sessid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'players.playerattribute': {
|
||||
'Meta': {'object_name': 'PlayerAttribute'},
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'players.playerdb': {
|
||||
'Meta': {'object_name': 'PlayerDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'obj_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_objs': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'objs_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'players.playernick': {
|
||||
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'},
|
||||
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['players']
|
||||
106
src/players/migrations/0015_removing_obj.py
Normal file
106
src/players/migrations/0015_removing_obj.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Deleting field 'PlayerDB.db_obj'
|
||||
db.delete_column('players_playerdb', 'db_obj_id')
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Adding field 'PlayerDB.db_obj'
|
||||
db.add_column('players_playerdb', 'db_obj',
|
||||
self.gf('django.db.models.fields.related.ForeignKey')(related_name='obj_set', null=True, to=orm['objects.ObjectDB'], blank=True),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'objects.objectdb': {
|
||||
'Meta': {'object_name': 'ObjectDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||
'db_sessid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'players.playerattribute': {
|
||||
'Meta': {'object_name': 'PlayerAttribute'},
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'players.playerdb': {
|
||||
'Meta': {'object_name': 'PlayerDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_objs': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'objs_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'players.playernick': {
|
||||
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'},
|
||||
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
|
||||
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['players']
|
||||
|
|
@ -161,8 +161,9 @@ class PlayerDB(TypedObject):
|
|||
help_text="The <I>User</I> object holds django-specific authentication for each Player. A unique User should be created and tied to each Player, the two should never be switched or changed around. The User will be deleted automatically when the Player is.")
|
||||
# the in-game object connected to this player (if any).
|
||||
# Use the property 'obj' to access.
|
||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True,
|
||||
verbose_name="character", help_text='In-game object.')
|
||||
db_objs = models.ManyToManyField("objects.ObjectDB", null=True,
|
||||
verbose_name="characters", related_name="objs_set",
|
||||
help_text="In-game objects.")
|
||||
# store a connected flag here too, not just in sessionhandler.
|
||||
# This makes it easier to track from various out-of-process locations
|
||||
db_is_connected = models.BooleanField(default=False, verbose_name="is_connected", help_text="If player is connected to game or not")
|
||||
|
|
@ -195,11 +196,12 @@ class PlayerDB(TypedObject):
|
|||
|
||||
# obj property (wraps db_obj)
|
||||
#@property
|
||||
def obj_get(self):
|
||||
def objs_get(self):
|
||||
"Getter. Allows for value = self.obj"
|
||||
return get_field_cache(self, "obj")
|
||||
return self.db_objs.all()
|
||||
#return get_field_cache(self, "objs").all()
|
||||
#@obj.setter
|
||||
def obj_set(self, value):
|
||||
def objs_set(self, value):
|
||||
"Setter. Allows for self.obj = value"
|
||||
global _TYPECLASS
|
||||
if not _TYPECLASS:
|
||||
|
|
@ -208,15 +210,19 @@ class PlayerDB(TypedObject):
|
|||
if isinstance(value, _TYPECLASS):
|
||||
value = value.dbobj
|
||||
try:
|
||||
set_field_cache(self, "obj", value)
|
||||
self.db_objs.add(value)
|
||||
self.save()
|
||||
#set_field_cache(self, "obj", value)
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
raise Exception("Cannot assign %s as a player object!" % value)
|
||||
#@obj.deleter
|
||||
def obj_del(self):
|
||||
def objs_del(self):
|
||||
"Deleter. Allows for del self.obj"
|
||||
del_field_cache(self, "obj")
|
||||
obj = property(obj_get, obj_set, obj_del)
|
||||
self.db_objs.clear()
|
||||
self.save()
|
||||
#del_field_cache(self, "obj")
|
||||
objs = property(objs_get, objs_set, objs_del)
|
||||
|
||||
# whereas the name 'obj' is consistent with the rest of the code,
|
||||
# 'character' is a more intuitive property name, so we
|
||||
|
|
@ -236,6 +242,7 @@ class PlayerDB(TypedObject):
|
|||
"Deleter. Allows for del self.character"
|
||||
del_field_cache(self, "obj")
|
||||
character = property(character_get, character_set, character_del)
|
||||
|
||||
# cmdset_storage property
|
||||
# This seems very sensitive to caching, so leaving it be for now /Griatch
|
||||
#@property
|
||||
|
|
@ -358,32 +365,219 @@ class PlayerDB(TypedObject):
|
|||
# PlayerDB class access methods
|
||||
#
|
||||
|
||||
def msg(self, outgoing_string, from_obj=None, data=None):
|
||||
def msg(self, outgoing_string, from_obj=None, data=None, sessid=None):
|
||||
"""
|
||||
Evennia -> User
|
||||
This is the main route for sending data back to the user from the server.
|
||||
|
||||
outgoing_string (string) - text data to send
|
||||
from_obj (Object/Player) - source object of message to send
|
||||
data (dict) - arbitrary data object containing eventual protocol-specific options
|
||||
sessid - the session id of the session to send to. If not given, return to
|
||||
all sessions connected to this player. This is usually only
|
||||
relevant when using msg() directly from a player-command (from
|
||||
a command on a Character, the character automatically stores and
|
||||
handles the sessid).
|
||||
"""
|
||||
if from_obj:
|
||||
# call hook
|
||||
try:
|
||||
_GA(from_obj, "at_msg_send")(outgoing_string, to_obj=self, data=data)
|
||||
except Exception:
|
||||
pass
|
||||
if (_GA(self, "character") and not
|
||||
_GA(self, "character").at_msg_receive(outgoing_string, from_obj=from_obj, data=data)):
|
||||
# the at_msg_receive() hook may block receiving of certain messages
|
||||
return
|
||||
|
||||
outgoing_string = utils.to_str(outgoing_string, force_string=True)
|
||||
|
||||
for session in _GA(self, 'sessions'):
|
||||
session = None
|
||||
if sessid:
|
||||
session = _GA(self, "get_session")(sessid)
|
||||
if session:
|
||||
char = _GA(self, "get_character")(sessid=sessid)
|
||||
if char and not char.at_msg_receive(outgoing_string, from_obj=from_obj, data=data):
|
||||
# if hook returns false, cancel send
|
||||
return
|
||||
session.msg(outgoing_string, data)
|
||||
else:
|
||||
# if no session was specified, send to them all
|
||||
for sess in _GA(self, 'get_all_sessions')():
|
||||
sess.msg(outgoing_string, data)
|
||||
|
||||
def inmsg(self, ingoing_string, sessid):
|
||||
"""
|
||||
User -> Evennia
|
||||
This is the reverse of msg - used by sessions to relay
|
||||
messages/data back into the game. It is normally not called
|
||||
from inside game code but only by the serversessions directly.
|
||||
|
||||
ingoing_string - text string (i.e. command string)
|
||||
data - dictionary of optional data
|
||||
session - session sending this data
|
||||
"""
|
||||
character = _GA(self, "get_character")(sessid=sessid)
|
||||
if character:
|
||||
# execute command on character
|
||||
_GA(character, "execute_cmd")(ingoing_string, sessid=sessid)
|
||||
else:
|
||||
# a non-character session; this goes to player directly
|
||||
_GA(self, "execute_cmd")(ingoing_string, sessid=sessid)
|
||||
|
||||
def connect_session_to_character(self, sessid, character, force=False):
|
||||
"""
|
||||
Connect the given session to a character through this player.
|
||||
Note that this assumes the character has previously been
|
||||
linked to the player using self.connect_character().
|
||||
|
||||
force - drop existing connection to other character
|
||||
|
||||
Returns True if connection was successful, False otherwise
|
||||
"""
|
||||
# first check if we already have a character tied to this session
|
||||
char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True)
|
||||
if char:
|
||||
if force and char != character:
|
||||
_GA(self, "disconnect_session_from_character")(sessid)
|
||||
else:
|
||||
return
|
||||
# do the connection
|
||||
character.sessid = sessid
|
||||
# update cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
cache[sessid] = character
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
# call hooks
|
||||
character.at_init()
|
||||
if character:
|
||||
# start (persistent) scripts on this object
|
||||
#ScriptDB.objects.validate(obj=character)
|
||||
pass
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
character.at_pre_login()
|
||||
character.at_post_login()
|
||||
return True
|
||||
|
||||
def disconnect_session_from_character(self, sessid):
|
||||
"""
|
||||
Disconnect a session from the characterm (still keeping the
|
||||
connection to the Player)
|
||||
returns the newly disconnected character, if it existed
|
||||
"""
|
||||
if not sessid:
|
||||
return
|
||||
char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True)
|
||||
if char:
|
||||
# call hook before disconnecting
|
||||
_GA(char.typeclass, "at_disconnect")()
|
||||
del char.sessid
|
||||
# update cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
if sessid in cache:
|
||||
del cache[sessid]
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
return char
|
||||
|
||||
def get_session(self, sessid):
|
||||
"""
|
||||
Return session with given sessid connected to this player.
|
||||
"""
|
||||
return SESSIONS.sessions_from_player(self, sessid=sessid)
|
||||
|
||||
def get_all_sessions(self):
|
||||
"Return all sessions connected to this player"
|
||||
return SESSIONS.sessions_from_player(self)
|
||||
|
||||
def get_character(self, sessid=None, character=None, return_dbobj=False):
|
||||
"""
|
||||
Get the character connected to this player and sessid
|
||||
|
||||
sessid - return character connected to this sessid,
|
||||
character - return character if connected to this player, else None.
|
||||
|
||||
Combining both keywords will check the entire connection - if the
|
||||
given session is currently connected to the given char. If no
|
||||
keywords are given, returns all connected characters.
|
||||
"""
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
if sessid:
|
||||
# try to return a character with a given sessid
|
||||
char = cache.get(sessid)
|
||||
if not char:
|
||||
char = _GA(self, "db_objs").filter(db_player=self, db_sessid=sessid) or None
|
||||
if char:
|
||||
char = char[0]
|
||||
cache[sessid] = char
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
if character:
|
||||
return char and (char == character.dbobj and (return_dbobj and char or char.typeclass)) or None
|
||||
return char and (return_dbobj and char or char.typeclass) or None
|
||||
elif character:
|
||||
char = _GA(self, "db_objs").filter(id=_GA(character.dbobj, "id"))
|
||||
return char and (return_dbobj and char[0] or char[0].typeclass) or None
|
||||
else:
|
||||
# no sessid given - return all available characters
|
||||
return list(return_dbobj and o or o.typeclass for o in self.db_objs.all())
|
||||
|
||||
def get_all_characters(self):
|
||||
"""
|
||||
Readability-wrapper for getting all characters
|
||||
"""
|
||||
return _GA(self, "get_character")(sessid=None, character=None)
|
||||
|
||||
def connect_character(self, character, sessid=None):
|
||||
"""
|
||||
Use the Player to connect a Character to a session. Note that
|
||||
we don't do any access checks at this point. Note that if the
|
||||
game was fully restarted (including the Portal), this must be
|
||||
used, since sessids will have changed as players reconnect.
|
||||
|
||||
if sessid is given, also connect the sessid to the character.
|
||||
"""
|
||||
# first disconnect any other character from this session
|
||||
char = character.dbobj
|
||||
_GA(self, "disconnect_character")(char)
|
||||
char.player = self
|
||||
_GA(self, "db_objs").add(char)
|
||||
_GA(self, "save")()
|
||||
if sessid:
|
||||
return _GA(self, "connect_session_to_character")(sessid=sessid, character=char)
|
||||
return True
|
||||
|
||||
def disconnect_character(self, character):
|
||||
"""
|
||||
Disconnect a character from this player, either based
|
||||
on sessid or by giving the character object directly
|
||||
|
||||
Returns newly disconnected character.
|
||||
"""
|
||||
if not character:
|
||||
return
|
||||
char = _GA(self, "get_character")(character=character, return_dbobj=True)
|
||||
if char:
|
||||
err = _GA(self, "disconnect_session_from_character")(char.sessid)
|
||||
_GA(self, "db_objs").remove(char)
|
||||
del char.player
|
||||
self.save()
|
||||
# clear cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
[cache.pop(sessid) for sessid,stored_char in cache.items() if stored_char==char]
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
return char
|
||||
|
||||
|
||||
def swap_character(self, new_character, delete_old_character=False):
|
||||
def disconnect_all_characters(self):
|
||||
for char in self.db_objs.all():
|
||||
_GA(self, "disconnect_character")(char)
|
||||
|
||||
def swap_character(self, old_character, new_character):
|
||||
"""
|
||||
Swaps character, if possible
|
||||
Swaps character between sessions, if possible
|
||||
"""
|
||||
return _GA(self, "__class__").objects.swap_character(self, new_character, delete_old_character=delete_old_character)
|
||||
this_sessid = old_character.sessid
|
||||
other_sessd = new_character.sessid
|
||||
this_char = _GA(self, "disconnect_session_from_character")(this_sessid)
|
||||
other_char = _GA(self, "disconnect_session_from_character")(other_sessid)
|
||||
_GA(self, "connect_session_to_character")(this_sessid, other_char)
|
||||
_GA(self, "connect_session_to_character")(other_sessid, this_char)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
"Make sure to delete user also when deleting player - the two may never exist separately."
|
||||
|
|
@ -401,7 +595,7 @@ class PlayerDB(TypedObject):
|
|||
# Execution/action methods
|
||||
#
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Do something as this player. This command transparently
|
||||
lets its typeclass execute the command.
|
||||
|
|
@ -417,7 +611,7 @@ class PlayerDB(TypedObject):
|
|||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
return cmdhandler.cmdhandler(self.typeclass, raw_string)
|
||||
return cmdhandler.cmdhandler(self.typeclass, raw_string, sessid=sessid)
|
||||
|
||||
def search(self, ostring, return_character=False):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -88,17 +88,21 @@ class Player(TypeClass):
|
|||
|
||||
## methods inherited from database model
|
||||
|
||||
def msg(self, outgoing_string, from_obj=None, data=None):
|
||||
def msg(self, outgoing_string, from_obj=None, data=None, sessid=None):
|
||||
"""
|
||||
Evennia -> User
|
||||
This is the main route for sending data back to the user from the server.
|
||||
|
||||
outgoing_string (string) - text data to send
|
||||
from_obj (Object/Player) - source object of message to send
|
||||
data (?) - arbitrary data object containing eventual protocol-specific options
|
||||
|
||||
"""
|
||||
self.dbobj.msg(outgoing_string, from_obj=from_obj, data=data)
|
||||
data (dict) - arbitrary data object containing eventual protocol-specific options
|
||||
sessid - the session id of the session to send to. If not given, return to
|
||||
all sessions connected to this player. This is usually only
|
||||
relevant when using msg() directly from a player-command (from
|
||||
a command on a Character, the character automatically stores and
|
||||
handles the sessid).
|
||||
"""
|
||||
self.dbobj.msg(outgoing_string, from_obj=from_obj, data=data, sessid=sessid)
|
||||
|
||||
def swap_character(self, new_character, delete_old_character=False):
|
||||
"""
|
||||
|
|
@ -111,7 +115,7 @@ class Player(TypeClass):
|
|||
"""
|
||||
return self.dbobj.swap_character(new_character, delete_old_character=delete_old_character)
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
|
|
@ -119,6 +123,7 @@ class Player(TypeClass):
|
|||
|
||||
Argument:
|
||||
raw_string (string) - raw command input
|
||||
sessid (int) - id of session executing the command. This sets the sessid property on the command
|
||||
|
||||
Returns Deferred - this is an asynchronous Twisted object that will
|
||||
not fire until the command has actually finished executing. To overload
|
||||
|
|
@ -129,7 +134,7 @@ class Player(TypeClass):
|
|||
This return is not used at all by Evennia by default, but might be useful
|
||||
for coders intending to implement some sort of nested command structure.
|
||||
"""
|
||||
return self.dbobj.execute_cmd(raw_string)
|
||||
return self.dbobj.execute_cmd(raw_string, sessid=sessid)
|
||||
|
||||
def search(self, ostring, return_character=False):
|
||||
"""
|
||||
|
|
@ -241,8 +246,9 @@ class Player(TypeClass):
|
|||
to store attributes all players should have,
|
||||
like configuration values etc.
|
||||
"""
|
||||
pass
|
||||
|
||||
# set an attribute holding the characters this player has
|
||||
lockstring = "attrread:perm(Admins);attredit:perm(Admins);attrcreate:perm(Admins)"
|
||||
self.set_attribute("_playable_characters", [], lockstring=lockstring)
|
||||
|
||||
def at_init(self):
|
||||
"""
|
||||
|
|
@ -293,8 +299,7 @@ class Player(TypeClass):
|
|||
"""
|
||||
# Character.at_post_login also looks around. Only use
|
||||
# this as a backup when logging in without a character
|
||||
if not self.character:
|
||||
self.execute_cmd("look")
|
||||
self.execute_cmd("look")
|
||||
|
||||
def at_disconnect(self, reason=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -52,10 +52,8 @@ def create_objects():
|
|||
# exists. Also, all properties (name, email, password, is_superuser)
|
||||
# is inherited from the user so we don't specify it again here.
|
||||
|
||||
god_character = create.create_player(god_user.username, None, None,
|
||||
user=god_user,
|
||||
create_character=True,
|
||||
character_typeclass=character_typeclass)
|
||||
god_player = create.create_player(god_user.username, None, None, user=god_user)
|
||||
god_character = create.create_object(character_typeclass, key=god_user.username)
|
||||
|
||||
god_character.id = 1
|
||||
god_character.db.desc = _('This is User #1.')
|
||||
|
|
@ -83,6 +81,8 @@ def create_objects():
|
|||
god_character.location = limbo_obj
|
||||
if not god_character.home:
|
||||
god_character.home = limbo_obj
|
||||
# store in list as playable character
|
||||
god_player.db._playable_characters.append(god_character)
|
||||
|
||||
def create_channels():
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -190,6 +190,9 @@ class Evennia(object):
|
|||
from src.objects.models import ObjectDB
|
||||
#from src.players.models import PlayerDB
|
||||
|
||||
# clear eventual lingering session storages
|
||||
ObjectDB.objects.clear_all_sessids()
|
||||
|
||||
#update eventual changed defaults
|
||||
self.update_defaults()
|
||||
|
||||
|
|
@ -288,7 +291,7 @@ class Evennia(object):
|
|||
|
||||
yield [(p.typeclass, p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()]
|
||||
yield [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()]
|
||||
|
||||
yield ObjectDB.objects.clear_all_sessids()
|
||||
ServerConfig.objects.conf("server_restart_mode", "reset")
|
||||
|
||||
if SERVER_STARTSTOP_MODULE:
|
||||
|
|
|
|||
|
|
@ -57,10 +57,6 @@ class ServerSession(Session):
|
|||
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):
|
||||
"""
|
||||
|
|
@ -91,38 +87,24 @@ class ServerSession(Session):
|
|||
self.user.save()
|
||||
|
||||
# player init
|
||||
#print "at_init() - player"
|
||||
player.at_init()
|
||||
|
||||
# Check if this is the first time the *player* logs in
|
||||
if player.db.FIRST_LOGIN:
|
||||
player.at_first_login()
|
||||
del player.db.FIRST_LOGIN
|
||||
player.at_pre_login()
|
||||
|
||||
character = player.character
|
||||
if character:
|
||||
# this player has a character. Check if it's the
|
||||
# first time *this character* logs in
|
||||
character.at_init()
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
# run character login hook
|
||||
character.at_pre_login()
|
||||
player.at_pre_login()
|
||||
|
||||
self.log(_('Logged in: %(self)s') % {'self': self})
|
||||
|
||||
# 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
|
||||
self.sessionhandler.login(self)
|
||||
|
||||
# post-login hooks
|
||||
player.at_post_login()
|
||||
if character:
|
||||
character.at_post_login()
|
||||
|
||||
def session_disconnect(self):
|
||||
"""
|
||||
|
|
@ -131,10 +113,10 @@ class ServerSession(Session):
|
|||
accounts.
|
||||
"""
|
||||
if self.logged_in:
|
||||
player = self.get_player()
|
||||
character = self.get_character()
|
||||
if character:
|
||||
character.at_disconnect()
|
||||
sessid = self.sessid
|
||||
player = self.player
|
||||
if player.get_character(sessid):
|
||||
player.disconnect_session_from_character(sessid)
|
||||
uaccount = player.user
|
||||
uaccount.last_login = datetime.now()
|
||||
uaccount.save()
|
||||
|
|
@ -154,10 +136,7 @@ class ServerSession(Session):
|
|||
Returns the in-game character associated with this session.
|
||||
This returns the typeclass of the object.
|
||||
"""
|
||||
player = self.get_player()
|
||||
if player:
|
||||
return player.character
|
||||
return None
|
||||
return self.logged_in and self.player.get_character(self.sessid) or None
|
||||
|
||||
def log(self, message, channel=True):
|
||||
"""
|
||||
|
|
@ -193,20 +172,13 @@ 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()
|
||||
if character:
|
||||
character.execute_cmd(command_string)
|
||||
if self.logged_in:
|
||||
# the inmsg handler will relay to the right place
|
||||
self.player.inmsg(command_string, self.sessid)
|
||||
else:
|
||||
if self.logged_in:
|
||||
# there is no character, but we are logged in. Use player instead.
|
||||
self.get_player().execute_cmd(command_string)
|
||||
else:
|
||||
# we are not logged in. Use the session directly
|
||||
# (it uses the settings.UNLOGGEDIN cmdset)
|
||||
cmdhandler.cmdhandler(self, command_string)
|
||||
self.update_session_counters()
|
||||
# we are not logged in. Use the session directly
|
||||
# (it uses the settings.UNLOGGEDIN cmdset)
|
||||
cmdhandler.cmdhandler(self, command_string, sessid=self.sessid)
|
||||
|
||||
def data_out(self, msg, data=None):
|
||||
"""
|
||||
|
|
@ -243,11 +215,11 @@ class ServerSession(Session):
|
|||
func = OOB_FUNC_MODULE.__dict__.get(functuple[0])
|
||||
if func:
|
||||
try:
|
||||
outdata[funcname] = func(oobkey, self, *functuple[1], **functuple[2])
|
||||
outdata[functuple[0]] = func(oobkey, self, *functuple[1], **functuple[2])
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
else:
|
||||
logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % funcname)
|
||||
logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % functuple[0])
|
||||
if outdata:
|
||||
# we have a direct result - send it back right away
|
||||
self.oob_data_out(outdata)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ SSYNC = chr(8) # server session sync
|
|||
from django.utils.translation import ugettext as _
|
||||
|
||||
SERVERNAME = settings.SERVERNAME
|
||||
ALLOW_MULTISESSION = settings.ALLOW_MULTISESSION
|
||||
#ALLOW_MULTISESSION = settings.ALLOW_MULTISESSION
|
||||
MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||
IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||
|
||||
#-----------------------------------------------------------
|
||||
|
|
@ -163,8 +164,8 @@ class ServerSessionHandler(SessionHandler):
|
|||
"""
|
||||
# prep the session with player/user info
|
||||
|
||||
if not ALLOW_MULTISESSION:
|
||||
# disconnect previous sessions.
|
||||
if MULTISESSION_MODE == 0:
|
||||
# disconnect all previous sessions.
|
||||
self.disconnect_duplicate_sessions(session)
|
||||
session.logged_in = True
|
||||
# sync the portal to this session
|
||||
|
|
@ -222,26 +223,30 @@ class ServerSessionHandler(SessionHandler):
|
|||
|
||||
def player_count(self):
|
||||
"""
|
||||
Get the number of connected players (not sessions since a player
|
||||
may have more than one session connected if ALLOW_MULTISESSION is True)
|
||||
Get the number of connected players (not sessions since a
|
||||
player may have more than one session depending on settings).
|
||||
Only logged-in players are counted here.
|
||||
"""
|
||||
return len(set(session.uid for session in self.sessions.values() if session.logged_in))
|
||||
|
||||
def sessions_from_player(self, player):
|
||||
def sessions_from_player(self, player, sessid=None):
|
||||
"""
|
||||
Given a player, return any matching sessions.
|
||||
"""
|
||||
uid = player.uid
|
||||
return [session for session in self.sessions.values() if session.logged_in and session.uid == uid]
|
||||
if sessid:
|
||||
session = self.sessions.get(sessid)
|
||||
return session and session.logged_in and session.uid == uid and session or None
|
||||
else:
|
||||
return [session for session in self.sessions.values() if session.logged_in and session.uid == uid]
|
||||
|
||||
def sessions_from_character(self, character):
|
||||
"""
|
||||
Given a game character, return any matching sessions.
|
||||
"""
|
||||
player = character.player
|
||||
if player:
|
||||
return self.sessions_from_player(player)
|
||||
sessid = character.sessid
|
||||
if sessid:
|
||||
return self.sessions.get(sessid)
|
||||
return None
|
||||
|
||||
def announce_all(self, message):
|
||||
|
|
|
|||
|
|
@ -62,12 +62,12 @@ SSL_ENABLED = False
|
|||
SSL_PORTS = [4001]
|
||||
# Interface addresses to listen to. If 0.0.0.0, listen to all.
|
||||
SSL_INTERFACES = ['0.0.0.0']
|
||||
# If multisessions are allowed, a user can log into the game
|
||||
# from several different computers/clients at the same time.
|
||||
# All feedback from the game will be echoed to all sessions.
|
||||
# If false, only one session is allowed, all other are logged off
|
||||
# when a new connects.
|
||||
ALLOW_MULTISESSION = False
|
||||
# Multisession modes allow a player (=account) to connect to the game simultaneously
|
||||
# with multiple clients in various ways according to the set mode:
|
||||
# 0 - no multisession - when a new session is connected, the old one is disconnected
|
||||
# 1 - multiple sessions, one player, one character, each session getting the same data
|
||||
# 2 - multiple sessions, one player, each session controlling different characters
|
||||
MULTISESSION_MODE = 0
|
||||
# The path that contains this settings.py file (no trailing slash).
|
||||
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
# Path to the src directory containing the bulk of the codebase's code.
|
||||
|
|
|
|||
|
|
@ -1311,7 +1311,7 @@ class TypedObject(SharedMemoryModel):
|
|||
return False
|
||||
return True
|
||||
|
||||
def set_attribute(self, attribute_name, new_value=None):
|
||||
def set_attribute(self, attribute_name, new_value=None, lockstring=""):
|
||||
"""
|
||||
Sets an attribute on an object. Creates the attribute if need
|
||||
be.
|
||||
|
|
@ -1319,6 +1319,10 @@ class TypedObject(SharedMemoryModel):
|
|||
attribute_name: (str) The attribute's name.
|
||||
new_value: (python obj) The value to set the attribute to. If this is not
|
||||
a str, the object will be stored as a pickle.
|
||||
lockstring - this sets an access restriction on the attribute object. Note that
|
||||
this is normally NOT checked - use the secureattr() access method
|
||||
below to perform access-checked modification of attributes. Lock
|
||||
types checked by secureattr are 'attrread','attredit','attrcreate'.
|
||||
"""
|
||||
attrib_obj = get_attr_cache(self, attribute_name)
|
||||
if not attrib_obj:
|
||||
|
|
@ -1332,6 +1336,8 @@ class TypedObject(SharedMemoryModel):
|
|||
else:
|
||||
# no match; create new attribute
|
||||
attrib_obj = attrclass(db_key=attribute_name, db_obj=self)
|
||||
if lockstring:
|
||||
attrib_obj.locks.add(lockstring)
|
||||
# re-set an old attribute value
|
||||
try:
|
||||
attrib_obj.value = new_value
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ class TypeClass(object):
|
|||
"""
|
||||
if propname == 'dbobj':
|
||||
return _GA(self, 'dbobj')
|
||||
if propname == 'typeclass':
|
||||
return self
|
||||
if propname.startswith('__') and propname.endswith('__'):
|
||||
# python specials are parsed as-is (otherwise things like
|
||||
# isinstance() fail to identify the typeclass)
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ _GA = object.__getattribute__
|
|||
#
|
||||
|
||||
def create_object(typeclass, key=None, location=None,
|
||||
home=None, player=None, permissions=None, locks=None,
|
||||
home=None, permissions=None, locks=None,
|
||||
aliases=None, destination=None, report_to=None):
|
||||
"""
|
||||
Create a new in-game object. Any game object is a combination
|
||||
|
|
@ -116,11 +116,6 @@ def create_object(typeclass, key=None, location=None,
|
|||
# from now on we can use the typeclass object
|
||||
# as if it was the database object.
|
||||
|
||||
if player:
|
||||
# link a player and the object together
|
||||
new_object.player = player
|
||||
player.obj = new_object
|
||||
|
||||
new_object.destination = destination
|
||||
|
||||
# call the hook method. This is where all at_creation
|
||||
|
|
@ -397,11 +392,8 @@ def create_player(name, email, password,
|
|||
typeclass=None,
|
||||
is_superuser=False,
|
||||
locks=None, permissions=None,
|
||||
create_character=True, character_typeclass=None,
|
||||
character_location=None, character_home=None,
|
||||
player_dbobj=None, report_to=None):
|
||||
|
||||
|
||||
"""
|
||||
This creates a new player, handling the creation of the User
|
||||
object and its associated Player object.
|
||||
|
|
@ -500,6 +492,7 @@ def create_player(name, email, password,
|
|||
# call hook method (may override default permissions)
|
||||
new_player.at_player_creation()
|
||||
|
||||
print
|
||||
# custom given arguments potentially overrides the hook
|
||||
if permissions:
|
||||
new_player.permissions = permissions
|
||||
|
|
@ -509,19 +502,8 @@ def create_player(name, email, password,
|
|||
if locks:
|
||||
new_player.locks.add(locks)
|
||||
|
||||
# create *in-game* 'player' object
|
||||
if create_character:
|
||||
if not character_typeclass:
|
||||
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
# creating the object automatically links the player
|
||||
# and object together by player.obj <-> obj.player
|
||||
new_character = create_object(character_typeclass, key=name,
|
||||
location=character_location, home=character_location,
|
||||
permissions=permissions,
|
||||
player=new_player, report_to=report_to)
|
||||
return new_character
|
||||
return new_player
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
# a failure in creating the character
|
||||
if not user:
|
||||
# in there was a failure we clean up everything we can
|
||||
|
|
@ -538,7 +520,7 @@ def create_player(name, email, password,
|
|||
del new_character
|
||||
except Exception:
|
||||
pass
|
||||
raise e
|
||||
raise
|
||||
|
||||
# alias
|
||||
player = create_player
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue