mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Rework at_before_say/at_say to handle whispers and using kwargs.
This commit is contained in:
commit
c43059c75f
153 changed files with 4418 additions and 2931 deletions
338
bin/project_rename.py
Normal file
338
bin/project_rename.py
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
"""
|
||||
Project rename utility
|
||||
|
||||
Created for the Player->Account renaming
|
||||
|
||||
Griatch 2017, released under the BSD license.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import fnmatch
|
||||
|
||||
ANSI_HILITE = "\033[1m"
|
||||
ANSI_RED = "\033[31m"
|
||||
ANSI_GREEN = "\033[32m"
|
||||
ANSI_YELLOW = "\033[33m"
|
||||
ANSI_NORMAL = "\033[0m"
|
||||
|
||||
USE_COLOR = True
|
||||
FAKE_MODE = False
|
||||
|
||||
# if these words are longer than output word, retain given case
|
||||
CASE_WORD_EXCEPTIONS = ('an', )
|
||||
|
||||
_HELP_TEXT = """This program interactively renames words in all files of your project. It's
|
||||
currently renaming {sources} to {targets}.
|
||||
|
||||
If it wants to replace text in a file, it will show all lines (and line numbers) it wants to
|
||||
replace, each directly followed by the suggested replacement.
|
||||
|
||||
If a rename is not okay, you can de-select it by entering 'i' followed by one or more
|
||||
comma-separated line numbers. You cannot ignore partial lines, those you need to remember to change
|
||||
manually later.
|
||||
|
||||
[q]uit - exits the program immediately.
|
||||
[h]elp - this help.
|
||||
[s]kip file - make no changes at all in this file, continue on to the next.
|
||||
[i]ignore lines - specify line numbers to not change.
|
||||
[c]lear ignores - this reverts all your ignores if you make a mistake.
|
||||
[a]accept/save file - apply all accepted renames and continue on to the next file.
|
||||
|
||||
(return to continue)
|
||||
"""
|
||||
|
||||
# Helper functions
|
||||
|
||||
def _green(string):
|
||||
if USE_COLOR:
|
||||
return "%s%s%s" % (ANSI_GREEN, string, ANSI_NORMAL)
|
||||
return string
|
||||
|
||||
|
||||
def _yellow(string):
|
||||
if USE_COLOR:
|
||||
return "%s%s%s" % (ANSI_YELLOW, string, ANSI_NORMAL)
|
||||
return string
|
||||
|
||||
|
||||
def _red(string):
|
||||
if USE_COLOR:
|
||||
return "%s%s%s" % (ANSI_HILITE + ANSI_RED, string, ANSI_NORMAL)
|
||||
return string
|
||||
|
||||
|
||||
def _case_sensitive_replace(string, old, new):
|
||||
"""
|
||||
Replace text, retaining exact case.
|
||||
|
||||
Args:
|
||||
string (str): String in which to perform replacement.
|
||||
old (str): Word or substring to replace.
|
||||
new (str): What to replace `old` with.
|
||||
|
||||
Returns:
|
||||
repl_string (str): Version of string where instances of
|
||||
`old` has been replaced with `new`, retaining case.
|
||||
|
||||
"""
|
||||
def repl(match):
|
||||
current = match.group()
|
||||
# treat multi-word sentences word-by-word
|
||||
old_words = current.split(" ")
|
||||
new_words = new.split(" ")
|
||||
out = []
|
||||
for old_word, new_word in zip(old_words, new_words):
|
||||
result = []
|
||||
all_upper = True
|
||||
for ind, chr in enumerate(old_word):
|
||||
if ind >= len(new):
|
||||
break
|
||||
if chr.isupper():
|
||||
result.append(new_word[ind].upper())
|
||||
else:
|
||||
result.append(new_word[ind].lower())
|
||||
all_upper = False
|
||||
# special cases - keep remaing case)
|
||||
if new_word.lower() in CASE_WORD_EXCEPTIONS:
|
||||
result.append(new_word[ind+1:])
|
||||
# append any remaining characters from new
|
||||
elif all_upper:
|
||||
result.append(new_word[ind+1:].upper())
|
||||
else:
|
||||
result.append(new_word[ind+1:].lower())
|
||||
out.append("".join(result))
|
||||
# if we have more new words than old ones, just add them verbatim
|
||||
out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)])
|
||||
return " ".join(out)
|
||||
|
||||
regex = re.compile(re.escape(old), re.I)
|
||||
return regex.sub(repl, string)
|
||||
|
||||
|
||||
def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interactive):
|
||||
"""
|
||||
Rename across a recursive directory structure.
|
||||
|
||||
Args:
|
||||
path (str): Root directory to traverse. All subdirectories
|
||||
will be visited.
|
||||
in_list (list): List of src words to replace.
|
||||
out_list (list): Matching list of words to replace with.
|
||||
excl_list (list): List of paths to exclude.
|
||||
fileend_list (list): List of file endings to accept. If
|
||||
not given, accept all file endings.
|
||||
is_interactive (bool): If we should stop to ask about the
|
||||
replacements in each file.
|
||||
|
||||
"""
|
||||
repl_mapping = zip(in_list, out_list)
|
||||
|
||||
for root, dirs, files in os.walk(path):
|
||||
|
||||
print("\ndir: %s\n" % root)
|
||||
|
||||
if any(fnmatch.fnmatch(root, excl) for excl in excl_list):
|
||||
print("%s skipped (excluded)." % root)
|
||||
continue
|
||||
|
||||
for file in files:
|
||||
|
||||
full_path = os.path.join(root, file)
|
||||
if any(fnmatch.fnmatch(full_path, excl) for excl in excl_list):
|
||||
print("%s skipped (excluded)." % full_path)
|
||||
continue
|
||||
|
||||
if not fileend_list or any(file.endswith(ending) for ending in fileend_list):
|
||||
rename_in_file(full_path, in_list, out_list, is_interactive)
|
||||
|
||||
# rename file - always ask
|
||||
new_file = file
|
||||
for src, dst in repl_mapping:
|
||||
new_file = _case_sensitive_replace(new_file, src, dst)
|
||||
if new_file != file:
|
||||
inp = raw_input(_green("Rename %s\n -> %s\n Y/[N]? > " % (file, new_file)))
|
||||
if inp.upper() == 'Y':
|
||||
new_full_path = os.path.join(root, new_file)
|
||||
try:
|
||||
os.rename(full_path, new_full_path)
|
||||
except OSError as err:
|
||||
raw_input(_red("Could not rename - %s (return to skip)" % err))
|
||||
else:
|
||||
print("... Renamed.")
|
||||
else:
|
||||
print("... Skipped.")
|
||||
# rename the dir
|
||||
new_root = root
|
||||
for src, dst in repl_mapping:
|
||||
new_root = _case_sensitive_replace(new_root, src, dst)
|
||||
if new_root != root:
|
||||
inp = raw_input(_green("Dir Rename %s\n -> %s\n Y/[N]? > " % (root, new_root)))
|
||||
if inp.upper() == 'Y':
|
||||
new_full_path = os.path.join(root, new_file)
|
||||
try:
|
||||
os.rename(root, new_root)
|
||||
except OSError as err:
|
||||
raw_input(_red("Could not rename - %s (return to skip)" % err))
|
||||
else:
|
||||
print("... Renamed.")
|
||||
else:
|
||||
print("... Skipped.")
|
||||
|
||||
|
||||
def rename_in_file(path, in_list, out_list, is_interactive):
|
||||
"""
|
||||
Args:
|
||||
path (str): Path to file in which to perform renaming.
|
||||
in_list (list): List of src words to replace.
|
||||
out_list (list): Matching list of words to replace with.
|
||||
is_interactive (bool): If we should stop to ask about the
|
||||
replacements in each file.
|
||||
|
||||
"""
|
||||
print("-- %s" % path)
|
||||
|
||||
org_text = ""
|
||||
new_text = None
|
||||
if os.path.isdir(path):
|
||||
print("%s is a directory. You should use the --recursive option." % path)
|
||||
sys.exit()
|
||||
|
||||
with open(path, 'r') as fil:
|
||||
org_text = fil.read()
|
||||
|
||||
repl_mapping = zip(in_list, out_list)
|
||||
|
||||
if not is_interactive:
|
||||
# just replace everything immediately
|
||||
new_text = org_text
|
||||
for src, dst in repl_mapping:
|
||||
new_text = _case_sensitive_replace(new_text, src, dst)
|
||||
if new_text != org_text:
|
||||
if FAKE_MODE:
|
||||
print(" ... Saved changes to %s. (faked)" % path)
|
||||
else:
|
||||
with open(path, 'w') as fil:
|
||||
fil.write(new_text)
|
||||
print(" ... Saved changes to %s." % path)
|
||||
else:
|
||||
# interactive mode
|
||||
while True:
|
||||
renamed = {}
|
||||
|
||||
org_lines = org_text.split("\n")
|
||||
|
||||
for iline, old_line in enumerate(org_lines):
|
||||
new_line = old_line
|
||||
for src, dst in repl_mapping:
|
||||
new_line = _case_sensitive_replace(new_line, src, dst)
|
||||
if new_line != old_line:
|
||||
renamed[iline] = new_line
|
||||
|
||||
if not renamed:
|
||||
# no changes
|
||||
print(" ... no changes to %s." % path)
|
||||
return
|
||||
|
||||
while True:
|
||||
|
||||
for iline, renamed_line in sorted(renamed.items(), key=lambda tup: tup[0]):
|
||||
print("%3i orig: %s" % (iline + 1, org_lines[iline]))
|
||||
print(" new : %s" % (_yellow(renamed_line)))
|
||||
print(_green("%s (%i lines changed)" % (path, len(renamed))))
|
||||
|
||||
ret = raw_input(_green("Choose: "
|
||||
"[q]uit, "
|
||||
"[h]elp, "
|
||||
"[s]kip file, "
|
||||
"[i]gnore lines, "
|
||||
"[c]lear ignores, "
|
||||
"[a]ccept/save file: ".lower()))
|
||||
|
||||
if ret == "s":
|
||||
# skip file entirely
|
||||
print(" ... Skipping file %s." % path)
|
||||
return
|
||||
elif ret == "c":
|
||||
# clear ignores - rerun rename
|
||||
break
|
||||
elif ret == "a":
|
||||
# save result
|
||||
for iline, renamed_line in renamed.items():
|
||||
org_lines[iline] = renamed_line
|
||||
|
||||
if FAKE_MODE:
|
||||
print(" ... Saved file %s (faked)" % path)
|
||||
return
|
||||
with open(path, 'w') as fil:
|
||||
fil.writelines("\n".join(org_lines))
|
||||
print(" ... Saved file %s" % path)
|
||||
return
|
||||
elif ret == "q":
|
||||
print("Quit renaming program.")
|
||||
sys.exit()
|
||||
elif ret == "h":
|
||||
raw_input(_HELP_TEXT.format(sources=in_list, targets=out_list))
|
||||
elif ret.startswith("i"):
|
||||
# ignore one or more lines
|
||||
ignores = [int(ind)-1 for ind in ret[1:].split(',') if ind.strip().isdigit()]
|
||||
if not ignores:
|
||||
raw_input("Ignore example: i 2,7,34,133\n (return to continue)")
|
||||
continue
|
||||
for ign in ignores:
|
||||
renamed.pop(ign, None)
|
||||
continue
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Rename text in a source tree, or a single file")
|
||||
|
||||
parser.add_argument('-i', '--input', action='append',
|
||||
help="Source word to rename (quote around multiple words)")
|
||||
parser.add_argument('-o', '--output', action='append',
|
||||
help="Word to rename a matching src-word to")
|
||||
parser.add_argument('-x', '--exc', action='append',
|
||||
help="File path patterns to exclude")
|
||||
parser.add_argument('-a', '--auto', action='store_true',
|
||||
help="Automatic mode, don't ask to rename")
|
||||
parser.add_argument('-r', '--recursive', action='store_true',
|
||||
help="Recurse subdirs")
|
||||
parser.add_argument('-f', '--fileending', action='append',
|
||||
help="Change which file endings to allow (default .py)")
|
||||
parser.add_argument('--nocolor', action='store_true',
|
||||
help="Turn off in-program color")
|
||||
parser.add_argument('--fake', action='store_true',
|
||||
help="Simulate run but don't actually save")
|
||||
parser.add_argument('path',
|
||||
help="File or directory in which to rename text")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
in_list, out_list, exc_list, fileend_list = args.input, args.output, args.exc, args.fileending
|
||||
|
||||
if not (in_list and out_list):
|
||||
print('At least one source- and destination word must be given.')
|
||||
sys.exit()
|
||||
if len(in_list) != len(out_list):
|
||||
print('Number of sources must be identical to the number of destination arguments.')
|
||||
sys.exit()
|
||||
|
||||
exc_list = exc_list or []
|
||||
fileend_list = fileend_list or [".py"]
|
||||
is_interactive = not args.auto
|
||||
is_recursive = args.recursive
|
||||
|
||||
USE_COLOR = not args.nocolor
|
||||
FAKE_MODE = args.fake
|
||||
|
||||
if is_recursive:
|
||||
rename_in_tree(args.path, in_list, out_list, exc_list, fileend_list, is_interactive)
|
||||
else:
|
||||
rename_in_file(args.path, in_list, out_list, is_interactive)
|
||||
|
|
@ -25,7 +25,7 @@ from builtins import object
|
|||
|
||||
# Typeclasses
|
||||
|
||||
DefaultPlayer = None
|
||||
DefaultAccount = None
|
||||
DefaultGuest = None
|
||||
DefaultObject = None
|
||||
DefaultCharacter = None
|
||||
|
|
@ -36,7 +36,7 @@ DefaultScript = None
|
|||
|
||||
# Database models
|
||||
ObjectDB = None
|
||||
PlayerDB = None
|
||||
AccountDB = None
|
||||
ScriptDB = None
|
||||
ChannelDB = None
|
||||
Msg = None
|
||||
|
|
@ -51,7 +51,7 @@ InterruptCommand = None
|
|||
# search functions
|
||||
search_object = None
|
||||
search_script = None
|
||||
search_player = None
|
||||
search_account = None
|
||||
search_channel = None
|
||||
search_message = None
|
||||
search_help = None
|
||||
|
|
@ -60,7 +60,7 @@ search_tag = None
|
|||
# create functions
|
||||
create_object = None
|
||||
create_script = None
|
||||
create_player = None
|
||||
create_account = None
|
||||
create_channel = None
|
||||
create_message = None
|
||||
create_help_entry = None
|
||||
|
|
@ -117,17 +117,17 @@ def _init():
|
|||
Evennia has fully initialized all its models. It sets up the API
|
||||
in a safe environment where all models are available already.
|
||||
"""
|
||||
global DefaultPlayer, DefaultObject, DefaultGuest, DefaultCharacter
|
||||
global DefaultAccount, DefaultObject, DefaultGuest, DefaultCharacter
|
||||
global DefaultRoom, DefaultExit, DefaultChannel, DefaultScript
|
||||
global ObjectDB, PlayerDB, ScriptDB, ChannelDB, Msg
|
||||
global ObjectDB, AccountDB, ScriptDB, ChannelDB, Msg
|
||||
global Command, CmdSet, default_cmds, syscmdkeys, InterruptCommand
|
||||
global search_object, search_script, search_player, search_channel, search_help, search_tag
|
||||
global create_object, create_script, create_player, create_channel, create_message, create_help_entry
|
||||
global search_object, search_script, search_account, search_channel, search_help, search_tag
|
||||
global create_object, create_script, create_account, create_channel, create_message, create_help_entry
|
||||
global settings,lockfuncs, logger, utils, gametime, ansi, spawn, managers
|
||||
global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, CHANNEL_HANDLER
|
||||
|
||||
from .players.players import DefaultPlayer
|
||||
from .players.players import DefaultGuest
|
||||
from .accounts.accounts import DefaultAccount
|
||||
from .accounts.accounts import DefaultGuest
|
||||
from .objects.objects import DefaultObject
|
||||
from .objects.objects import DefaultCharacter
|
||||
from .objects.objects import DefaultRoom
|
||||
|
|
@ -137,7 +137,7 @@ def _init():
|
|||
|
||||
# Database models
|
||||
from .objects.models import ObjectDB
|
||||
from .players.models import PlayerDB
|
||||
from .accounts.models import AccountDB
|
||||
from .scripts.models import ScriptDB
|
||||
from .comms.models import ChannelDB
|
||||
from .comms.models import Msg
|
||||
|
|
@ -149,7 +149,7 @@ def _init():
|
|||
# search functions
|
||||
from .utils.search import search_object
|
||||
from .utils.search import search_script
|
||||
from .utils.search import search_player
|
||||
from .utils.search import search_account
|
||||
from .utils.search import search_message
|
||||
from .utils.search import search_channel
|
||||
from .utils.search import search_help
|
||||
|
|
@ -158,7 +158,7 @@ def _init():
|
|||
# create functions
|
||||
from .utils.create import create_object
|
||||
from .utils.create import create_script
|
||||
from .utils.create import create_player
|
||||
from .utils.create import create_account
|
||||
from .utils.create import create_channel
|
||||
from .utils.create import create_message
|
||||
from .utils.create import create_help_entry
|
||||
|
|
@ -202,7 +202,7 @@ def _init():
|
|||
Links to instantiated database managers.
|
||||
|
||||
helpentry - HelpEntry.objects
|
||||
players - PlayerDB.objects
|
||||
accounts - AccountDB.objects
|
||||
scripts - ScriptDB.objects
|
||||
msgs - Msg.objects
|
||||
channels - Channel.objects
|
||||
|
|
@ -213,7 +213,7 @@ def _init():
|
|||
|
||||
"""
|
||||
from .help.models import HelpEntry
|
||||
from .players.models import PlayerDB
|
||||
from .accounts.models import AccountDB
|
||||
from .scripts.models import ScriptDB
|
||||
from .comms.models import Msg, ChannelDB
|
||||
from .objects.models import ObjectDB
|
||||
|
|
@ -223,7 +223,7 @@ def _init():
|
|||
|
||||
# create container's properties
|
||||
helpentries = HelpEntry.objects
|
||||
players = PlayerDB.objects
|
||||
accounts = AccountDB.objects
|
||||
scripts = ScriptDB.objects
|
||||
msgs = Msg.objects
|
||||
channels = ChannelDB.objects
|
||||
|
|
@ -232,7 +232,7 @@ def _init():
|
|||
attributes = Attribute.objects
|
||||
tags = Tag.objects
|
||||
# remove these so they are not visible as properties
|
||||
del HelpEntry, PlayerDB, ScriptDB, Msg, ChannelDB
|
||||
del HelpEntry, AccountDB, ScriptDB, Msg, ChannelDB
|
||||
#del ExternalChannelConnection
|
||||
del ObjectDB, ServerConfig, Tag, Attribute
|
||||
|
||||
|
|
@ -250,10 +250,10 @@ def _init():
|
|||
"""
|
||||
|
||||
from .commands.default.cmdset_character import CharacterCmdSet
|
||||
from .commands.default.cmdset_player import PlayerCmdSet
|
||||
from .commands.default.cmdset_account import AccountCmdSet
|
||||
from .commands.default.cmdset_unloggedin import UnloggedinCmdSet
|
||||
from .commands.default.cmdset_session import SessionCmdSet
|
||||
from .commands.default.muxcommand import MuxCommand, MuxPlayerCommand
|
||||
from .commands.default.muxcommand import MuxCommand, MuxAccountCommand
|
||||
|
||||
def __init__(self):
|
||||
"populate the object with commands"
|
||||
|
|
@ -265,14 +265,14 @@ def _init():
|
|||
|
||||
from .commands.default import (admin, batchprocess,
|
||||
building, comms, general,
|
||||
player, help, system, unloggedin)
|
||||
account, help, system, unloggedin)
|
||||
add_cmds(admin)
|
||||
add_cmds(building)
|
||||
add_cmds(batchprocess)
|
||||
add_cmds(building)
|
||||
add_cmds(comms)
|
||||
add_cmds(general)
|
||||
add_cmds(player)
|
||||
add_cmds(account)
|
||||
add_cmds(help)
|
||||
add_cmds(system)
|
||||
add_cmds(unloggedin)
|
||||
|
|
@ -293,7 +293,7 @@ def _init():
|
|||
CMD_MULTIMATCH - multiple command matches were found
|
||||
CMD_CHANNEL - the command name is a channel name
|
||||
CMD_LOGINSTART - this command will be called as the very
|
||||
first command when a player connects to
|
||||
first command when an account connects to
|
||||
the server.
|
||||
|
||||
To access in code, do 'from evennia import syscmdkeys' then
|
||||
|
|
|
|||
6
evennia/accounts/__init__.py
Normal file
6
evennia/accounts/__init__.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
"""
|
||||
This sub-package defines the out-of-character entities known as
|
||||
Accounts. These are equivalent to 'accounts' and can puppet one or
|
||||
more Objects depending on settings. An Account has no in-game existence.
|
||||
|
||||
"""
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Typeclass for Player objects
|
||||
Typeclass for Account objects
|
||||
|
||||
Note that this object is primarily intended to
|
||||
store OOC information, not game info! This
|
||||
|
|
@ -15,8 +15,8 @@ import time
|
|||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from evennia.typeclasses.models import TypeclassBase
|
||||
from evennia.players.manager import PlayerManager
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.accounts.manager import AccountManager
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.comms.models import ChannelDB
|
||||
from evennia.commands import cmdhandler
|
||||
|
|
@ -31,32 +31,32 @@ from evennia.commands.cmdsethandler import CmdSetHandler
|
|||
from django.utils.translation import ugettext as _
|
||||
from future.utils import with_metaclass
|
||||
|
||||
__all__ = ("DefaultPlayer",)
|
||||
__all__ = ("DefaultAccount",)
|
||||
|
||||
_SESSIONS = None
|
||||
|
||||
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||
_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
|
||||
_CMDSET_PLAYER = settings.CMDSET_PLAYER
|
||||
_CMDSET_ACCOUNT = settings.CMDSET_ACCOUNT
|
||||
_CONNECT_CHANNEL = None
|
||||
|
||||
|
||||
class PlayerSessionHandler(object):
|
||||
class AccountSessionHandler(object):
|
||||
"""
|
||||
Manages the session(s) attached to a player.
|
||||
Manages the session(s) attached to an account.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, player):
|
||||
def __init__(self, account):
|
||||
"""
|
||||
Initializes the handler.
|
||||
|
||||
Args:
|
||||
player (Player): The Player on which this handler is defined.
|
||||
account (Account): The Account on which this handler is defined.
|
||||
|
||||
"""
|
||||
self.player = player
|
||||
self.account = account
|
||||
|
||||
def get(self, sessid=None):
|
||||
"""
|
||||
|
|
@ -75,9 +75,9 @@ class PlayerSessionHandler(object):
|
|||
if not _SESSIONS:
|
||||
from evennia.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
if sessid:
|
||||
return make_iter(_SESSIONS.session_from_player(self.player, sessid))
|
||||
return make_iter(_SESSIONS.session_from_account(self.account, sessid))
|
||||
else:
|
||||
return _SESSIONS.sessions_from_player(self.player)
|
||||
return _SESSIONS.sessions_from_account(self.account)
|
||||
|
||||
def all(self):
|
||||
"""
|
||||
|
|
@ -100,19 +100,19 @@ class PlayerSessionHandler(object):
|
|||
return len(self.get())
|
||||
|
||||
|
||||
class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
||||
class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
||||
"""
|
||||
This is the base Typeclass for all Players. Players represent
|
||||
This is the base Typeclass for all Accounts. Accounts represent
|
||||
the person playing the game and tracks account info, password
|
||||
etc. They are OOC entities without presence in-game. A Player
|
||||
etc. They are OOC entities without presence in-game. An Account
|
||||
can connect to a Character Object in order to "enter" the
|
||||
game.
|
||||
|
||||
Player Typeclass API:
|
||||
Account Typeclass API:
|
||||
|
||||
* Available properties (only available on initiated typeclass objects)
|
||||
|
||||
- key (string) - name of player
|
||||
- key (string) - name of account
|
||||
- name (string)- wrapper for user.username
|
||||
- aliases (list of strings) - aliases to the object. Will be saved to
|
||||
database as AliasDB entries but returned as strings.
|
||||
|
|
@ -120,9 +120,9 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
- date_created (string) - time stamp of object creation
|
||||
- permissions (list of strings) - list of permission strings
|
||||
- user (User, read-only) - django User authorization object
|
||||
- obj (Object) - game object controlled by player. 'character' can also
|
||||
- obj (Object) - game object controlled by account. 'character' can also
|
||||
be used.
|
||||
- sessions (list of Sessions) - sessions connected to this player
|
||||
- sessions (list of Sessions) - sessions connected to this account
|
||||
- is_superuser (bool, read-only) - if the connected user is a superuser
|
||||
|
||||
* Handlers
|
||||
|
|
@ -142,7 +142,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
- execute_cmd(raw_string)
|
||||
- search(ostring, global_search=False, attribute_name=None,
|
||||
use_nicks=False, location=None,
|
||||
ignore_errors=False, player=False)
|
||||
ignore_errors=False, account=False)
|
||||
- is_typeclass(typeclass, exact=False)
|
||||
- swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
|
||||
- access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False)
|
||||
|
|
@ -151,7 +151,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
* Hook methods
|
||||
|
||||
basetype_setup()
|
||||
at_player_creation()
|
||||
at_account_creation()
|
||||
|
||||
> note that the following hooks are also found on Objects and are
|
||||
usually handled on the character level:
|
||||
|
|
@ -169,7 +169,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
"""
|
||||
|
||||
objects = PlayerManager()
|
||||
objects = AccountManager()
|
||||
|
||||
# properties
|
||||
@lazy_property
|
||||
|
|
@ -186,14 +186,14 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
@lazy_property
|
||||
def sessions(self):
|
||||
return PlayerSessionHandler(self)
|
||||
return AccountSessionHandler(self)
|
||||
|
||||
# session-related methods
|
||||
|
||||
def disconnect_session_from_player(self, session):
|
||||
def disconnect_session_from_account(self, session):
|
||||
"""
|
||||
Access method for disconnecting a given session from the
|
||||
player (connection happens automatically in the
|
||||
account (connection happens automatically in the
|
||||
sessionhandler)
|
||||
|
||||
Args:
|
||||
|
|
@ -235,9 +235,9 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
# no access
|
||||
self.msg("You don't have permission to puppet '%s'." % obj.key)
|
||||
return
|
||||
if obj.player:
|
||||
if obj.account:
|
||||
# object already puppeted
|
||||
if obj.player == self:
|
||||
if obj.account == self:
|
||||
if obj.sessions.count():
|
||||
# we may take over another of our sessions
|
||||
# output messages to the affected sessions
|
||||
|
|
@ -252,9 +252,9 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
self.msg(txt1 % obj.name, session=session)
|
||||
self.msg(txt2 % obj.name, session=obj.sessions.all())
|
||||
self.unpuppet_object(obj.sessions.get())
|
||||
elif obj.player.is_connected:
|
||||
# controlled by another player
|
||||
self.msg("|c%s|R is already puppeted by another Player." % obj.key)
|
||||
elif obj.account.is_connected:
|
||||
# controlled by another account
|
||||
self.msg("|c%s|R is already puppeted by another Account." % obj.key)
|
||||
return
|
||||
|
||||
# do the puppeting
|
||||
|
|
@ -262,14 +262,14 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
# cleanly unpuppet eventual previous object puppeted by this session
|
||||
self.unpuppet_object(session)
|
||||
# if we get to this point the character is ready to puppet or it
|
||||
# was left with a lingering player/session reference from an unclean
|
||||
# was left with a lingering account/session reference from an unclean
|
||||
# server kill or similar
|
||||
|
||||
obj.at_pre_puppet(self, session=session)
|
||||
|
||||
# do the connection
|
||||
obj.sessions.add(session)
|
||||
obj.player = self
|
||||
obj.account = self
|
||||
session.puid = obj.id
|
||||
session.puppet = obj
|
||||
# validate/start persistent scripts on object
|
||||
|
|
@ -299,7 +299,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
obj.at_pre_unpuppet()
|
||||
obj.sessions.remove(session)
|
||||
if not obj.sessions.count():
|
||||
del obj.player
|
||||
del obj.account
|
||||
obj.at_post_unpuppet(self, session=session)
|
||||
# Just to be sure we're always clear.
|
||||
session.puppet = None
|
||||
|
|
@ -314,9 +314,9 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
def get_puppet(self, session):
|
||||
"""
|
||||
Get an object puppeted by this session through this player. This is
|
||||
Get an object puppeted by this session through this account. This is
|
||||
the main method for retrieving the puppeted object from the
|
||||
player's end.
|
||||
account's end.
|
||||
|
||||
Args:
|
||||
session (Session): Find puppeted object based on this session
|
||||
|
|
@ -333,7 +333,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
Returns:
|
||||
puppets (list): All puppeted objects currently controlled
|
||||
by this Player.
|
||||
by this Account.
|
||||
|
||||
"""
|
||||
return list(set(session.puppet for session in self.sessions.all() if session.puppet))
|
||||
|
|
@ -359,7 +359,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
def delete(self, *args, **kwargs):
|
||||
"""
|
||||
Deletes the player permanently.
|
||||
Deletes the account permanently.
|
||||
|
||||
Notes:
|
||||
`*args` and `**kwargs` are passed on to the base delete
|
||||
|
|
@ -375,12 +375,12 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
except RuntimeError:
|
||||
# no puppet to disconnect from
|
||||
pass
|
||||
session.sessionhandler.disconnect(session, reason=_("Player being deleted."))
|
||||
session.sessionhandler.disconnect(session, reason=_("Account being deleted."))
|
||||
self.scripts.stop()
|
||||
self.attributes.clear()
|
||||
self.nicks.clear()
|
||||
self.aliases.clear()
|
||||
super(DefaultPlayer, self).delete(*args, **kwargs)
|
||||
super(DefaultAccount, self).delete(*args, **kwargs)
|
||||
# methods inherited from database model
|
||||
|
||||
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
|
||||
|
|
@ -391,7 +391,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
Args:
|
||||
text (str, optional): text data to send
|
||||
from_obj (Object or Player, optional): Object sending. If given,
|
||||
from_obj (Object or Account, optional): Object sending. If given,
|
||||
its at_msg_send() hook will be called.
|
||||
session (Session or list, optional): Session object or a list of
|
||||
Sessions to receive this send. If given, overrules the
|
||||
|
|
@ -411,7 +411,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
pass
|
||||
try:
|
||||
if not self.at_msg_receive(text=text, **kwargs):
|
||||
# abort message to this player
|
||||
# abort message to this account
|
||||
return
|
||||
except Exception:
|
||||
# this may not be assigned.
|
||||
|
|
@ -426,9 +426,9 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
def execute_cmd(self, raw_string, session=None, **kwargs):
|
||||
"""
|
||||
Do something as this player. This method is never called normally,
|
||||
but only when the player object itself is supposed to execute the
|
||||
command. It takes player nicks into account, but not nicks of
|
||||
Do something as this account. This method is never called normally,
|
||||
but only when the account object itself is supposed to execute the
|
||||
command. It takes account nicks into account, but not nicks of
|
||||
eventual puppets.
|
||||
|
||||
Args:
|
||||
|
|
@ -445,33 +445,33 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
"""
|
||||
raw_string = to_unicode(raw_string)
|
||||
raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_player=False)
|
||||
raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_account=False)
|
||||
if not session and _MULTISESSION_MODE in (0, 1):
|
||||
# for these modes we use the first/only session
|
||||
sessions = self.sessions.get()
|
||||
session = sessions[0] if sessions else None
|
||||
|
||||
return cmdhandler.cmdhandler(self, raw_string,
|
||||
callertype="player", session=session, **kwargs)
|
||||
callertype="account", session=session, **kwargs)
|
||||
|
||||
def search(self, searchdata, return_puppet=False, search_object=False,
|
||||
typeclass=None, nofound_string=None, multimatch_string=None, **kwargs):
|
||||
"""
|
||||
This is similar to `DefaultObject.search` but defaults to searching
|
||||
for Players only.
|
||||
for Accounts only.
|
||||
|
||||
Args:
|
||||
searchdata (str or int): Search criterion, the Player's
|
||||
searchdata (str or int): Search criterion, the Account's
|
||||
key or dbref to search for.
|
||||
return_puppet (bool, optional): Instructs the method to
|
||||
return matches as the object the Player controls rather
|
||||
than the Player itself (or None) if nothing is puppeted).
|
||||
return matches as the object the Account controls rather
|
||||
than the Account itself (or None) if nothing is puppeted).
|
||||
search_object (bool, optional): Search for Objects instead of
|
||||
Players. This is used by e.g. the @examine command when
|
||||
Accounts. This is used by e.g. the @examine command when
|
||||
wanting to examine Objects while OOC.
|
||||
typeclass (Player typeclass, optional): Limit the search
|
||||
typeclass (Account typeclass, optional): Limit the search
|
||||
only to this particular typeclass. This can be used to
|
||||
limit to specific player typeclasses or to limit the search
|
||||
limit to specific account typeclasses or to limit the search
|
||||
to a particular Object typeclass if `search_object` is True.
|
||||
nofound_string (str, optional): A one-time error message
|
||||
to echo if `searchdata` leads to no matches. If not given,
|
||||
|
|
@ -481,7 +481,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
If not given, will fall back to the default handler.
|
||||
|
||||
Return:
|
||||
match (Player, Object or None): A single Player or Object match.
|
||||
match (Account, Object or None): A single Account or Object match.
|
||||
Notes:
|
||||
Extra keywords are ignored, but are allowed in call in
|
||||
order to make API more consistent with
|
||||
|
|
@ -496,7 +496,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
if search_object:
|
||||
matches = ObjectDB.objects.object_search(searchdata, typeclass=typeclass)
|
||||
else:
|
||||
matches = PlayerDB.objects.player_search(searchdata, typeclass=typeclass)
|
||||
matches = AccountDB.objects.account_search(searchdata, typeclass=typeclass)
|
||||
matches = _AT_SEARCH_RESULT(matches, self, query=searchdata,
|
||||
nofound_string=nofound_string,
|
||||
multimatch_string=multimatch_string)
|
||||
|
|
@ -527,7 +527,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
result (bool): Result of access check.
|
||||
|
||||
"""
|
||||
result = super(DefaultPlayer, self).access(accessing_obj, access_type=access_type,
|
||||
result = super(DefaultAccount, self).access(accessing_obj, access_type=access_type,
|
||||
default=default, no_superuser_bypass=no_superuser_bypass)
|
||||
self.at_access(result, accessing_obj, access_type, **kwargs)
|
||||
return result
|
||||
|
|
@ -554,31 +554,31 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
return time.time() - float(min(conn))
|
||||
return None
|
||||
|
||||
# player hooks
|
||||
# account hooks
|
||||
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
This sets up the basic properties for a player. Overload this
|
||||
with at_player_creation rather than changing this method.
|
||||
This sets up the basic properties for an account. Overload this
|
||||
with at_account_creation rather than changing this method.
|
||||
|
||||
"""
|
||||
# A basic security setup
|
||||
lockstring = "examine:perm(Wizards);edit:perm(Wizards);" \
|
||||
"delete:perm(Wizards);boot:perm(Wizards);msg:all()"
|
||||
lockstring = "examine:perm(Admin);edit:perm(Admin);" \
|
||||
"delete:perm(Admin);boot:perm(Admin);msg:all()"
|
||||
self.locks.add(lockstring)
|
||||
|
||||
# The ooc player cmdset
|
||||
self.cmdset.add_default(_CMDSET_PLAYER, permanent=True)
|
||||
# The ooc account cmdset
|
||||
self.cmdset.add_default(_CMDSET_ACCOUNT, permanent=True)
|
||||
|
||||
def at_player_creation(self):
|
||||
def at_account_creation(self):
|
||||
"""
|
||||
This is called once, the very first time the player is created
|
||||
This is called once, the very first time the account is created
|
||||
(i.e. first time they register with the game). It's a good
|
||||
place to store attributes all players should have, like
|
||||
place to store attributes all accounts should have, like
|
||||
configuration values etc.
|
||||
|
||||
"""
|
||||
# set an (empty) attribute holding the characters this player has
|
||||
# set an (empty) attribute holding the characters this account has
|
||||
lockstring = "attrread:perm(Admins);attredit:perm(Admins);" \
|
||||
"attrcreate:perm(Admins)"
|
||||
self.attributes.add("_playable_characters", [], lockstring=lockstring)
|
||||
|
|
@ -590,8 +590,8 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
that is, whenever it its typeclass is cached from memory. This
|
||||
happens on-demand first time the object is used or activated
|
||||
in some way after being created but also after each server
|
||||
restart or reload. In the case of player objects, this usually
|
||||
happens the moment the player logs in or reconnects after a
|
||||
restart or reload. In the case of account objects, this usually
|
||||
happens the moment the account logs in or reconnects after a
|
||||
reload.
|
||||
|
||||
"""
|
||||
|
|
@ -601,7 +601,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
# typeclass. You can often ignore these and rely on the character
|
||||
# ones instead, unless you are implementing a multi-character game
|
||||
# and have some things that should be done regardless of which
|
||||
# character is currently connected to this player.
|
||||
# character is currently connected to this account.
|
||||
|
||||
def at_first_save(self):
|
||||
"""
|
||||
|
|
@ -611,11 +611,11 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
"""
|
||||
self.basetype_setup()
|
||||
self.at_player_creation()
|
||||
self.at_account_creation()
|
||||
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
|
||||
if hasattr(self, "_createdict"):
|
||||
# this will only be set if the utils.create_player
|
||||
# this will only be set if the utils.create_account
|
||||
# function was used to create the object.
|
||||
cdict = self._createdict
|
||||
if cdict.get("locks"):
|
||||
|
|
@ -624,11 +624,11 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
permissions = cdict["permissions"]
|
||||
del self._createdict
|
||||
|
||||
self.permissions.add(permissions)
|
||||
self.permissions.batch_add(*permissions)
|
||||
|
||||
def at_access(self, result, accessing_obj, access_type, **kwargs):
|
||||
"""
|
||||
This is triggered after an access-call on this Player has
|
||||
This is triggered after an access-call on this Account has
|
||||
completed.
|
||||
|
||||
Args:
|
||||
|
|
@ -653,33 +653,41 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
def at_cmdset_get(self, **kwargs):
|
||||
"""
|
||||
Called just *before* cmdsets on this player are requested by
|
||||
Called just *before* cmdsets on this account are requested by
|
||||
the command handler. The cmdsets are available as
|
||||
`self.cmdset`. If changes need to be done on the fly to the
|
||||
cmdset before passing them on to the cmdhandler, this is the
|
||||
place to do it. This is called also if the player currently
|
||||
place to do it. This is called also if the account currently
|
||||
have no cmdsets. kwargs are usually not used unless the
|
||||
cmdset is generated dynamically.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_first_login(self):
|
||||
def at_first_login(self, **kwargs):
|
||||
"""
|
||||
Called the very first time this player logs into the game.
|
||||
Called the very first time this account logs into the game.
|
||||
Note that this is called *before* at_pre_login, so no session
|
||||
is established and usually no character is yet assigned at
|
||||
this point. This hook is intended for player-specific setup
|
||||
this point. This hook is intended for account-specific setup
|
||||
like configurations.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_pre_login(self):
|
||||
def at_pre_login(self, **kwargs):
|
||||
"""
|
||||
Called every time the user logs in, just before the actual
|
||||
login-state is set.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
@ -706,13 +714,15 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
else:
|
||||
logger.log_info("[%s]: %s" % (now, message))
|
||||
|
||||
def at_post_login(self, session=None):
|
||||
def at_post_login(self, session=None, **kwargs):
|
||||
"""
|
||||
Called at the end of the login process, just before letting
|
||||
the player loose.
|
||||
the account loose.
|
||||
|
||||
Args:
|
||||
session (Session, optional): Session logging in, if any.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
This is called *before* an eventual Character's
|
||||
|
|
@ -747,14 +757,14 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
return
|
||||
elif _MULTISESSION_MODE in (2, 3):
|
||||
# In this mode we by default end up at a character selection
|
||||
# screen. We execute look on the player.
|
||||
# screen. We execute look on the account.
|
||||
# we make sure to clean up the _playable_characers list in case
|
||||
# any was deleted in the interim.
|
||||
self.db._playable_characters = [char for char in self.db._playable_characters if char]
|
||||
self.msg(self.at_look(target=self.db._playable_characters,
|
||||
session=session))
|
||||
|
||||
def at_failed_login(self, session):
|
||||
def at_failed_login(self, session, **kwargs):
|
||||
"""
|
||||
Called by the login process if a user account is targeted correctly
|
||||
but provided with an invalid password. By default it does nothing,
|
||||
|
|
@ -762,42 +772,60 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
|
||||
Args:
|
||||
session (session): Session logging in.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_disconnect(self, reason=None):
|
||||
def at_disconnect(self, reason=None, **kwargs):
|
||||
"""
|
||||
Called just before user is disconnected.
|
||||
|
||||
Args:
|
||||
reason (str, optional): The reason given for the disconnect,
|
||||
(echoed to the connection channel by default).
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
|
||||
"""
|
||||
reason = reason and "(%s)" % reason or ""
|
||||
self._send_to_connect_channel("|R%s disconnected %s|n" % (self.key, reason))
|
||||
|
||||
def at_post_disconnect(self):
|
||||
def at_post_disconnect(self, **kwargs):
|
||||
"""
|
||||
This is called *after* disconnection is complete. No messages
|
||||
can be relayed to the player from here. After this call, the
|
||||
player should not be accessed any more, making this a good
|
||||
spot for deleting it (in the case of a guest player account,
|
||||
can be relayed to the account from here. After this call, the
|
||||
account should not be accessed any more, making this a good
|
||||
spot for deleting it (in the case of a guest account account,
|
||||
for example).
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_message_receive(self, message, from_obj=None):
|
||||
def at_message_receive(self, message, from_obj=None, **kwargs):
|
||||
"""
|
||||
This is currently unused.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
return True
|
||||
|
||||
def at_message_send(self, message, to_object):
|
||||
def at_message_send(self, message, to_object, **kwargs):
|
||||
"""
|
||||
This is currently unused.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
@ -817,7 +845,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_look(self, target=None, session=None):
|
||||
def at_look(self, target=None, session=None, **kwargs):
|
||||
"""
|
||||
Called when this object executes a look. It allows to customize
|
||||
just what this means.
|
||||
|
|
@ -826,6 +854,8 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
target (Object or list, optional): An object or a list
|
||||
objects to inspect.
|
||||
session (Session, optional): The session doing this look.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
look_string (str): A prepared look string, ready to send
|
||||
|
|
@ -893,18 +923,20 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
|
|||
return look_string
|
||||
|
||||
|
||||
class DefaultGuest(DefaultPlayer):
|
||||
class DefaultGuest(DefaultAccount):
|
||||
"""
|
||||
This class is used for guest logins. Unlike Players, Guests and
|
||||
This class is used for guest logins. Unlike Accounts, Guests and
|
||||
their characters are deleted after disconnection.
|
||||
"""
|
||||
def at_post_login(self, session=None):
|
||||
def at_post_login(self, session=None, **kwargs):
|
||||
"""
|
||||
In theory, guests only have one character regardless of which
|
||||
MULTISESSION_MODE we're in. They don't get a choice.
|
||||
|
||||
Args:
|
||||
session (Session, optional): Session connecting.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
self._send_to_connect_channel("|G%s connected|n" % self.key)
|
||||
|
|
@ -922,9 +954,14 @@ class DefaultGuest(DefaultPlayer):
|
|||
print "deleting Character:", character
|
||||
character.delete()
|
||||
|
||||
def at_post_disconnect(self):
|
||||
def at_post_disconnect(self, **kwargs):
|
||||
"""
|
||||
Once having disconnected, destroy the guest's characters and
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
super(DefaultGuest, self).at_post_disconnect()
|
||||
characters = self.db._playable_characters
|
||||
|
|
@ -9,19 +9,19 @@ from django.conf import settings
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.typeclasses.admin import AttributeInline, TagInline
|
||||
from evennia.utils import create
|
||||
|
||||
|
||||
# handle the custom User editor
|
||||
class PlayerDBChangeForm(UserChangeForm):
|
||||
class AccountDBChangeForm(UserChangeForm):
|
||||
"""
|
||||
Modify the playerdb class.
|
||||
Modify the accountdb class.
|
||||
|
||||
"""
|
||||
class Meta(object):
|
||||
model = PlayerDB
|
||||
model = AccountDB
|
||||
fields = '__all__'
|
||||
|
||||
username = forms.RegexField(
|
||||
|
|
@ -44,19 +44,19 @@ class PlayerDBChangeForm(UserChangeForm):
|
|||
username = self.cleaned_data['username']
|
||||
if username.upper() == self.instance.username.upper():
|
||||
return username
|
||||
elif PlayerDB.objects.filter(username__iexact=username):
|
||||
raise forms.ValidationError('A player with that name '
|
||||
elif AccountDB.objects.filter(username__iexact=username):
|
||||
raise forms.ValidationError('An account with that name '
|
||||
'already exists.')
|
||||
return self.cleaned_data['username']
|
||||
|
||||
|
||||
class PlayerDBCreationForm(UserCreationForm):
|
||||
class AccountDBCreationForm(UserCreationForm):
|
||||
"""
|
||||
Create a new PlayerDB instance.
|
||||
Create a new AccountDB instance.
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
model = PlayerDB
|
||||
model = AccountDB
|
||||
fields = '__all__'
|
||||
|
||||
username = forms.RegexField(
|
||||
|
|
@ -76,24 +76,24 @@ class PlayerDBCreationForm(UserCreationForm):
|
|||
Cleanup username.
|
||||
"""
|
||||
username = self.cleaned_data['username']
|
||||
if PlayerDB.objects.filter(username__iexact=username):
|
||||
raise forms.ValidationError('A player with that name already '
|
||||
if AccountDB.objects.filter(username__iexact=username):
|
||||
raise forms.ValidationError('An account with that name already '
|
||||
'exists.')
|
||||
return username
|
||||
|
||||
|
||||
class PlayerForm(forms.ModelForm):
|
||||
class AccountForm(forms.ModelForm):
|
||||
"""
|
||||
Defines how to display Players
|
||||
Defines how to display Accounts
|
||||
|
||||
"""
|
||||
class Meta(object):
|
||||
model = PlayerDB
|
||||
model = AccountDB
|
||||
fields = '__all__'
|
||||
|
||||
db_key = forms.RegexField(
|
||||
label="Username",
|
||||
initial="PlayerDummy",
|
||||
initial="AccountDummy",
|
||||
max_length=30,
|
||||
regex=r'^[\w. @+-]+$',
|
||||
required=False,
|
||||
|
|
@ -101,32 +101,32 @@ class PlayerForm(forms.ModelForm):
|
|||
error_messages={
|
||||
'invalid': "This value may contain only letters, spaces, numbers"
|
||||
" and @/./+/-/_ characters."},
|
||||
help_text="This should be the same as the connected Player's key "
|
||||
help_text="This should be the same as the connected Account's key "
|
||||
"name. 30 characters or fewer. Letters, spaces, digits and "
|
||||
"@/./+/-/_ only.")
|
||||
|
||||
db_typeclass_path = forms.CharField(
|
||||
label="Typeclass",
|
||||
initial=settings.BASE_PLAYER_TYPECLASS,
|
||||
initial=settings.BASE_ACCOUNT_TYPECLASS,
|
||||
widget=forms.TextInput(
|
||||
attrs={'size': '78'}),
|
||||
help_text="Required. Defines what 'type' of entity this is. This "
|
||||
"variable holds a Python path to a module with a valid "
|
||||
"Evennia Typeclass. Defaults to "
|
||||
"settings.BASE_PLAYER_TYPECLASS.")
|
||||
"settings.BASE_ACCOUNT_TYPECLASS.")
|
||||
|
||||
db_permissions = forms.CharField(
|
||||
label="Permissions",
|
||||
initial=settings.PERMISSION_PLAYER_DEFAULT,
|
||||
initial=settings.PERMISSION_ACCOUNT_DEFAULT,
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={'size': '78'}),
|
||||
help_text="In-game permissions. A comma-separated list of text "
|
||||
"strings checked by certain locks. They are often used for "
|
||||
"hierarchies, such as letting a Player have permission "
|
||||
"'Wizards', 'Builders' etc. A Player permission can be "
|
||||
"hierarchies, such as letting an Account have permission "
|
||||
"'Admin', 'Builder' etc. An Account permission can be "
|
||||
"overloaded by the permissions of a controlled Character. "
|
||||
"Normal players use 'Players' by default.")
|
||||
"Normal accounts use 'Accounts' by default.")
|
||||
|
||||
db_lock_storage = forms.CharField(
|
||||
label="Locks",
|
||||
|
|
@ -137,64 +137,64 @@ class PlayerForm(forms.ModelForm):
|
|||
"<i>type:lockfunction(args);type2:lockfunction2(args);...")
|
||||
db_cmdset_storage = forms.CharField(
|
||||
label="cmdset",
|
||||
initial=settings.CMDSET_PLAYER,
|
||||
initial=settings.CMDSET_ACCOUNT,
|
||||
widget=forms.TextInput(attrs={'size': '78'}),
|
||||
required=False,
|
||||
help_text="python path to player cmdset class (set in "
|
||||
"settings.CMDSET_PLAYER by default)")
|
||||
help_text="python path to account cmdset class (set in "
|
||||
"settings.CMDSET_ACCOUNT by default)")
|
||||
|
||||
|
||||
class PlayerInline(admin.StackedInline):
|
||||
class AccountInline(admin.StackedInline):
|
||||
"""
|
||||
Inline creation of Player
|
||||
Inline creation of Account
|
||||
|
||||
"""
|
||||
model = PlayerDB
|
||||
template = "admin/players/stacked.html"
|
||||
form = PlayerForm
|
||||
model = AccountDB
|
||||
template = "admin/accounts/stacked.html"
|
||||
form = AccountForm
|
||||
fieldsets = (
|
||||
("In-game Permissions and Locks",
|
||||
{'fields': ('db_lock_storage',),
|
||||
#{'fields': ('db_permissions', 'db_lock_storage'),
|
||||
'description': "<i>These are permissions/locks for in-game use. "
|
||||
"They are unrelated to website access rights.</i>"}),
|
||||
("In-game Player data",
|
||||
("In-game Account data",
|
||||
{'fields': ('db_typeclass_path', 'db_cmdset_storage'),
|
||||
'description': "<i>These fields define in-game-specific properties "
|
||||
"for the Player object in-game.</i>"}))
|
||||
"for the Account object in-game.</i>"}))
|
||||
|
||||
extra = 1
|
||||
max_num = 1
|
||||
|
||||
|
||||
class PlayerTagInline(TagInline):
|
||||
class AccountTagInline(TagInline):
|
||||
"""
|
||||
Inline Player Tags.
|
||||
Inline Account Tags.
|
||||
|
||||
"""
|
||||
model = PlayerDB.db_tags.through
|
||||
related_field = "playerdb"
|
||||
model = AccountDB.db_tags.through
|
||||
related_field = "accountdb"
|
||||
|
||||
|
||||
class PlayerAttributeInline(AttributeInline):
|
||||
class AccountAttributeInline(AttributeInline):
|
||||
"""
|
||||
Inline Player Attributes.
|
||||
Inline Account Attributes.
|
||||
|
||||
"""
|
||||
model = PlayerDB.db_attributes.through
|
||||
related_field = "playerdb"
|
||||
model = AccountDB.db_attributes.through
|
||||
related_field = "accountdb"
|
||||
|
||||
|
||||
class PlayerDBAdmin(BaseUserAdmin):
|
||||
class AccountDBAdmin(BaseUserAdmin):
|
||||
"""
|
||||
This is the main creation screen for Users/players
|
||||
This is the main creation screen for Users/accounts
|
||||
|
||||
"""
|
||||
|
||||
list_display = ('username', 'email', 'is_staff', 'is_superuser')
|
||||
form = PlayerDBChangeForm
|
||||
add_form = PlayerDBCreationForm
|
||||
inlines = [PlayerTagInline, PlayerAttributeInline]
|
||||
form = AccountDBChangeForm
|
||||
add_form = AccountDBCreationForm
|
||||
inlines = [AccountTagInline, AccountAttributeInline]
|
||||
fieldsets = (
|
||||
(None, {'fields': ('username', 'password', 'email')}),
|
||||
('Website profile', {
|
||||
|
|
@ -240,16 +240,16 @@ class PlayerDBAdmin(BaseUserAdmin):
|
|||
"""
|
||||
obj.save()
|
||||
if not change:
|
||||
#calling hooks for new player
|
||||
obj.set_class_from_typeclass(typeclass_path=settings.BASE_PLAYER_TYPECLASS)
|
||||
#calling hooks for new account
|
||||
obj.set_class_from_typeclass(typeclass_path=settings.BASE_ACCOUNT_TYPECLASS)
|
||||
obj.basetype_setup()
|
||||
obj.at_player_creation()
|
||||
obj.at_account_creation()
|
||||
|
||||
def response_add(self, request, obj, post_url_continue=None):
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.core.urlresolvers import reverse
|
||||
if '_continue' in request.POST:
|
||||
return HttpResponseRedirect(reverse("admin:players_playerdb_change", args=[obj.id]))
|
||||
return HttpResponseRedirect(reverse("admin:players_playerdb_change", args=[obj.id]))
|
||||
return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id]))
|
||||
return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id]))
|
||||
|
||||
admin.site.register(PlayerDB, PlayerDBAdmin)
|
||||
admin.site.register(AccountDB, AccountDBAdmin)
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
"""
|
||||
Bots are a special child typeclasses of
|
||||
Player that are controlled by the server.
|
||||
Account that are controlled by the server.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import time
|
||||
from django.conf import settings
|
||||
from evennia.players.players import DefaultPlayer
|
||||
from evennia.accounts.accounts import DefaultAccount
|
||||
from evennia.scripts.scripts import DefaultScript
|
||||
from evennia.utils import search
|
||||
from evennia.utils import utils
|
||||
|
|
@ -48,7 +48,7 @@ class BotStarter(DefaultScript):
|
|||
|
||||
"""
|
||||
if not self.db.started:
|
||||
self.player.start()
|
||||
self.account.start()
|
||||
self.db.started = True
|
||||
|
||||
def at_repeat(self):
|
||||
|
|
@ -63,7 +63,7 @@ class BotStarter(DefaultScript):
|
|||
global _SESSIONS
|
||||
if not _SESSIONS:
|
||||
from evennia.server.sessionhandler import SESSIONS as _SESSIONS
|
||||
for session in _SESSIONS.sessions_from_player(self.player):
|
||||
for session in _SESSIONS.sessions_from_account(self.account):
|
||||
session.update_session_counters(idle=True)
|
||||
|
||||
def at_server_reload(self):
|
||||
|
|
@ -85,7 +85,7 @@ class BotStarter(DefaultScript):
|
|||
# Bot base class
|
||||
|
||||
|
||||
class Bot(DefaultPlayer):
|
||||
class Bot(DefaultAccount):
|
||||
"""
|
||||
A Bot will start itself when the server starts (it will generally
|
||||
not do so on a reload - that will be handled by the normal Portal
|
||||
|
|
@ -101,7 +101,7 @@ class Bot(DefaultPlayer):
|
|||
# the text encoding to use.
|
||||
self.db.encoding = "utf-8"
|
||||
# A basic security setup
|
||||
lockstring = "examine:perm(Wizards);edit:perm(Wizards);delete:perm(Wizards);boot:perm(Wizards);msg:false()"
|
||||
lockstring = "examine:perm(Admin);edit:perm(Admin);delete:perm(Admin);boot:perm(Admin);msg:false()"
|
||||
self.locks.add(lockstring)
|
||||
# set the basics of being a bot
|
||||
script_key = "%s" % self.key
|
||||
|
|
@ -211,7 +211,7 @@ class IRCBot(Bot):
|
|||
Retrive the nick list from the connected channel.
|
||||
|
||||
Args:
|
||||
caller (Object or Player): The requester of the list. This will
|
||||
caller (Object or Account): The requester of the list. This will
|
||||
be stored and echoed to when the irc network replies with the
|
||||
requested info.
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ class IRCBot(Bot):
|
|||
Fire a ping to the IRC server.
|
||||
|
||||
Args:
|
||||
caller (Object or Player): The requester of the ping.
|
||||
caller (Object or Account): The requester of the ping.
|
||||
|
||||
"""
|
||||
if not hasattr(self, "_ping_callers"):
|
||||
|
|
@ -242,7 +242,7 @@ class IRCBot(Bot):
|
|||
def reconnect(self):
|
||||
"""
|
||||
Force a protocol-side reconnect of the client without
|
||||
having to destroy/recreate the bot "player".
|
||||
having to destroy/recreate the bot "account".
|
||||
|
||||
"""
|
||||
super(IRCBot, self).msg(reconnect="")
|
||||
|
|
@ -323,8 +323,8 @@ class IRCBot(Bot):
|
|||
for sess in _SESSIONS.get_sessions():
|
||||
delta_cmd = t0 - sess.cmd_last_visible
|
||||
delta_conn = t0 - session.conn_time
|
||||
player = sess.get_player()
|
||||
whos.append("%s (%s/%s)" % (utils.crop("|w%s|n" % player.name, width=25),
|
||||
account = sess.get_account()
|
||||
whos.append("%s (%s/%s)" % (utils.crop("|w%s|n" % account.name, width=25),
|
||||
utils.time_format(delta_conn, 0),
|
||||
utils.time_format(delta_cmd, 1)))
|
||||
text = "Who list (online/idle): %s" % ", ".join(sorted(whos, key=lambda w: w.lower()))
|
||||
|
|
@ -1,25 +1,22 @@
|
|||
"""
|
||||
The managers for the custom Player object and permissions.
|
||||
The managers for the custom Account object and permissions.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from django.utils import timezone
|
||||
from django.contrib.auth.models import UserManager
|
||||
#from functools import update_wrapper
|
||||
from evennia.typeclasses.managers import (returns_typeclass_list, returns_typeclass,
|
||||
TypedObjectManager, TypeclassManager)
|
||||
from evennia.utils.utils import make_iter
|
||||
__all__ = ("PlayerManager",)
|
||||
from evennia.typeclasses.managers import (TypedObjectManager, TypeclassManager)
|
||||
__all__ = ("AccountManager",)
|
||||
|
||||
|
||||
#
|
||||
# Player Manager
|
||||
# Account Manager
|
||||
#
|
||||
|
||||
class PlayerDBManager(TypedObjectManager, UserManager):
|
||||
class AccountDBManager(TypedObjectManager, UserManager):
|
||||
"""
|
||||
This PlayerManager implements methods for searching
|
||||
and manipulating Players directly from the database.
|
||||
This AccountManager implements methods for searching
|
||||
and manipulating Accounts directly from the database.
|
||||
|
||||
Evennia-specific search methods (will return Characters if
|
||||
possible or a Typeclass/list of Typeclassed objects, whereas
|
||||
|
|
@ -30,49 +27,47 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
get_dbref_range
|
||||
object_totals
|
||||
typeclass_search
|
||||
num_total_players
|
||||
get_connected_players
|
||||
get_recently_created_players
|
||||
get_recently_connected_players
|
||||
get_player_from_email
|
||||
get_player_from_uid
|
||||
get_player_from_name
|
||||
player_search (equivalent to evennia.search_player)
|
||||
num_total_accounts
|
||||
get_connected_accounts
|
||||
get_recently_created_accounts
|
||||
get_recently_connected_accounts
|
||||
get_account_from_email
|
||||
get_account_from_uid
|
||||
get_account_from_name
|
||||
account_search (equivalent to evennia.search_account)
|
||||
#swap_character
|
||||
|
||||
"""
|
||||
def num_total_players(self):
|
||||
def num_total_accounts(self):
|
||||
"""
|
||||
Get total number of players.
|
||||
Get total number of accounts.
|
||||
|
||||
Returns:
|
||||
count (int): The total number of registered players.
|
||||
count (int): The total number of registered accounts.
|
||||
|
||||
"""
|
||||
return self.count()
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_connected_players(self):
|
||||
def get_connected_accounts(self):
|
||||
"""
|
||||
Get all currently connected players.
|
||||
Get all currently connected accounts.
|
||||
|
||||
Returns:
|
||||
count (list): Player objects with currently
|
||||
count (list): Account objects with currently
|
||||
connected sessions.
|
||||
|
||||
"""
|
||||
return self.filter(db_is_connected=True)
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_recently_created_players(self, days=7):
|
||||
def get_recently_created_accounts(self, days=7):
|
||||
"""
|
||||
Get players recently created.
|
||||
Get accounts recently created.
|
||||
|
||||
Args:
|
||||
days (int, optional): How many days in the past "recently" means.
|
||||
|
||||
Returns:
|
||||
players (list): The Players created the last `days` interval.
|
||||
accounts (list): The Accounts created the last `days` interval.
|
||||
|
||||
"""
|
||||
end_date = timezone.now()
|
||||
|
|
@ -80,16 +75,15 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
start_date = end_date - tdelta
|
||||
return self.filter(date_joined__range=(start_date, end_date))
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_recently_connected_players(self, days=7):
|
||||
def get_recently_connected_accounts(self, days=7):
|
||||
"""
|
||||
Get players recently connected to the game.
|
||||
Get accounts recently connected to the game.
|
||||
|
||||
Args:
|
||||
days (int, optional): Number of days backwards to check
|
||||
|
||||
Returns:
|
||||
players (list): The Players connected to the game in the
|
||||
accounts (list): The Accounts connected to the game in the
|
||||
last `days` interval.
|
||||
|
||||
"""
|
||||
|
|
@ -99,31 +93,29 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
return self.filter(last_login__range=(
|
||||
start_date, end_date)).order_by('-last_login')
|
||||
|
||||
@returns_typeclass
|
||||
def get_player_from_email(self, uemail):
|
||||
def get_account_from_email(self, uemail):
|
||||
"""
|
||||
Search player by
|
||||
Returns a player object based on email address.
|
||||
Search account by
|
||||
Returns an account object based on email address.
|
||||
|
||||
Args:
|
||||
uemail (str): An email address to search for.
|
||||
|
||||
Returns:
|
||||
player (Player): A found player, if found.
|
||||
account (Account): A found account, if found.
|
||||
|
||||
"""
|
||||
return self.filter(email__iexact=uemail)
|
||||
|
||||
@returns_typeclass
|
||||
def get_player_from_uid(self, uid):
|
||||
def get_account_from_uid(self, uid):
|
||||
"""
|
||||
Get a player by id.
|
||||
Get an account by id.
|
||||
|
||||
Args:
|
||||
uid (int): Player database id.
|
||||
uid (int): Account database id.
|
||||
|
||||
Returns:
|
||||
player (Player): The result.
|
||||
account (Account): The result.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -131,16 +123,15 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
except self.model.DoesNotExist:
|
||||
return None
|
||||
|
||||
@returns_typeclass
|
||||
def get_player_from_name(self, uname):
|
||||
def get_account_from_name(self, uname):
|
||||
"""
|
||||
Get player object based on name.
|
||||
Get account object based on name.
|
||||
|
||||
Args:
|
||||
uname (str): The Player name to search for.
|
||||
uname (str): The Account name to search for.
|
||||
|
||||
Returns:
|
||||
player (Player): The found player.
|
||||
account (Account): The found account.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -148,10 +139,9 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
except self.model.DoesNotExist:
|
||||
return None
|
||||
|
||||
@returns_typeclass_list
|
||||
def search_player(self, ostring, exact=True, typeclass=None):
|
||||
def search_account(self, ostring, exact=True, typeclass=None):
|
||||
"""
|
||||
Searches for a particular player by name or
|
||||
Searches for a particular account by name or
|
||||
database id.
|
||||
|
||||
Args:
|
||||
|
|
@ -161,7 +151,7 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
otherwise also match also keys containing the `ostring`
|
||||
(non-case-sensitive fuzzy match).
|
||||
typeclass (str or Typeclass, optional): Limit the search only to
|
||||
players of this typeclass.
|
||||
accounts of this typeclass.
|
||||
|
||||
"""
|
||||
dbref = self.dbref(ostring)
|
||||
|
|
@ -183,7 +173,8 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
|||
else:
|
||||
return self.filter(**query)
|
||||
# back-compatibility alias
|
||||
player_search = search_player
|
||||
account_search = search_account
|
||||
|
||||
class PlayerManager(PlayerDBManager, TypeclassManager):
|
||||
|
||||
class AccountManager(AccountDBManager, TypeclassManager):
|
||||
pass
|
||||
|
|
@ -15,7 +15,7 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PlayerDB',
|
||||
name='AccountDB',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
|
|
@ -32,7 +32,7 @@ class Migration(migrations.Migration):
|
|||
('db_typeclass_path', models.CharField(help_text=b"this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.", max_length=255, null=True, verbose_name=b'typeclass')),
|
||||
('db_date_created', models.DateTimeField(auto_now_add=True, verbose_name=b'creation date')),
|
||||
('db_lock_storage', models.TextField(help_text=b"locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.", verbose_name=b'locks', blank=True)),
|
||||
('db_is_connected', models.BooleanField(default=False, help_text=b'If player is connected to game or not', verbose_name=b'is_connected')),
|
||||
('db_is_connected', models.BooleanField(default=False, help_text=b'If account is connected to game or not', verbose_name=b'is_connected')),
|
||||
('db_cmdset_storage', models.CharField(help_text=b'optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.', max_length=255, null=True, verbose_name=b'cmdset')),
|
||||
('db_is_bot', models.BooleanField(default=False, help_text=b'Used to identify irc/rss bots', verbose_name=b'is_bot')),
|
||||
('db_attributes', models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute', null=True)),
|
||||
|
|
@ -41,8 +41,8 @@ class Migration(migrations.Migration):
|
|||
('user_permissions', models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Permission', blank=True, help_text='Specific permissions for this user.', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Player',
|
||||
'verbose_name_plural': 'Players',
|
||||
'verbose_name': 'Account',
|
||||
'verbose_name_plural': 'Accounts',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
|
|
@ -4,15 +4,15 @@ from __future__ import unicode_literals
|
|||
from django.db import models, migrations
|
||||
|
||||
def convert_defaults(apps, schema_editor):
|
||||
PlayerDB = apps.get_model("players", "PlayerDB")
|
||||
for player in PlayerDB.objects.filter(db_typeclass_path="src.players.player.Player"):
|
||||
player.db_typeclass_path = "typeclasses.players.Player"
|
||||
player.save()
|
||||
AccountDB = apps.get_model("accounts", "AccountDB")
|
||||
for account in AccountDB.objects.filter(db_typeclass_path="src.accounts.account.Account"):
|
||||
account.db_typeclass_path = "typeclasses.accounts.Account"
|
||||
account.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('players', '0001_initial'),
|
||||
('accounts', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
|
@ -7,18 +7,18 @@ from django.db import models, migrations
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('players', '0002_move_defaults'),
|
||||
('accounts', '0002_move_defaults'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DefaultPlayer',
|
||||
name='DefaultAccount',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('players.playerdb',),
|
||||
bases=('accounts.accountdb',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='DefaultGuest',
|
||||
|
|
@ -27,10 +27,10 @@ class Migration(migrations.Migration):
|
|||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('players.defaultplayer',),
|
||||
bases=('accounts.defaultaccount',),
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='playerdb',
|
||||
options={'verbose_name': 'Player'},
|
||||
name='accountdb',
|
||||
options={'verbose_name': 'Account'},
|
||||
),
|
||||
]
|
||||
|
|
@ -2,14 +2,14 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import evennia.players.manager
|
||||
import evennia.accounts.manager
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('players', '0003_auto_20150209_2234'),
|
||||
('accounts', '0003_auto_20150209_2234'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
|
@ -17,31 +17,31 @@ class Migration(migrations.Migration):
|
|||
name='DefaultGuest',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='DefaultPlayer',
|
||||
name='DefaultAccount',
|
||||
),
|
||||
migrations.AlterModelManagers(
|
||||
name='playerdb',
|
||||
name='accountdb',
|
||||
managers=[
|
||||
(b'objects', evennia.players.manager.PlayerDBManager()),
|
||||
(b'objects', evennia.accounts.manager.AccountDBManager()),
|
||||
],
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='playerdb',
|
||||
model_name='accountdb',
|
||||
name='email',
|
||||
field=models.EmailField(max_length=254, verbose_name='email address', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='playerdb',
|
||||
model_name='accountdb',
|
||||
name='groups',
|
||||
field=models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', verbose_name='groups'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='playerdb',
|
||||
model_name='accountdb',
|
||||
name='last_login',
|
||||
field=models.DateTimeField(null=True, verbose_name='last login', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='playerdb',
|
||||
model_name='accountdb',
|
||||
name='username',
|
||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username'),
|
||||
),
|
||||
|
|
@ -9,12 +9,12 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('players', '0004_auto_20150403_2339'),
|
||||
('accounts', '0004_auto_20150403_2339'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='playerdb',
|
||||
model_name='accountdb',
|
||||
name='username',
|
||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')], verbose_name='username'),
|
||||
),
|
||||
31
evennia/accounts/migrations/0006_auto_20170606_1731.py
Normal file
31
evennia/accounts/migrations/0006_auto_20170606_1731.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-06 17:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0005_auto_20160905_0902'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='accountdb',
|
||||
name='db_attributes',
|
||||
field=models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accountdb',
|
||||
name='db_tags',
|
||||
field=models.ManyToManyField(help_text=b'tags on this object. Tags are simple string markers to identify, group and alias objects.', to='typeclasses.Tag'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accountdb',
|
||||
name='username',
|
||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.ASCIIUsernameValidator()], verbose_name='username'),
|
||||
),
|
||||
]
|
||||
58
evennia/accounts/migrations/0007_copy_player_to_account.py
Normal file
58
evennia/accounts/migrations/0007_copy_player_to_account.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-03 19:17
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import apps as global_apps
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
try:
|
||||
PlayerDB = apps.get_model('players', 'PlayerDB')
|
||||
except LookupError:
|
||||
# playerdb not available. Skip.
|
||||
return
|
||||
|
||||
AccountDB = apps.get_model('accounts', 'AccountDB')
|
||||
for player in PlayerDB.objects.all():
|
||||
account = AccountDB(id=player.id,
|
||||
password=player.password,
|
||||
is_superuser=player.is_superuser,
|
||||
last_login=player.last_login,
|
||||
username=player.username,
|
||||
first_name=player.first_name,
|
||||
last_name=player.last_name,
|
||||
email=player.email,
|
||||
is_staff=player.is_staff,
|
||||
is_active=player.is_active,
|
||||
date_joined=player.date_joined,
|
||||
db_key=player.db_key,
|
||||
db_typeclass_path=player.db_typeclass_path,
|
||||
db_date_created=player.db_date_created,
|
||||
db_lock_storage=player.db_lock_storage,
|
||||
db_is_connected=player.db_is_connected,
|
||||
db_cmdset_storage=player.db_cmdset_storage,
|
||||
db_is_bot=player.db_is_bot)
|
||||
account.save()
|
||||
for group in player.groups.all():
|
||||
account.groups.add(group)
|
||||
for user_permission in player.user_permissions.all():
|
||||
account.user_permissions.add(user_permission)
|
||||
for attr in player.db_attributes.all():
|
||||
account.db_attributes.add(attr)
|
||||
for tag in player.db_tags.all():
|
||||
account.db_tags.add(tag)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0006_auto_20170606_1731'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards, migrations.RunPython.noop)
|
||||
]
|
||||
|
||||
if global_apps.is_installed('players'):
|
||||
dependencies.append(('players', '0006_auto_20170606_1731'))
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
"""
|
||||
Player
|
||||
Account
|
||||
|
||||
The player class is an extension of the default Django user class,
|
||||
The account class is an extension of the default Django user class,
|
||||
and is customized for the needs of Evennia.
|
||||
|
||||
We use the Player to store a more mud-friendly style of permission
|
||||
We use the Account to store a more mud-friendly style of permission
|
||||
system as well as to allow the admin more flexibility by storing
|
||||
attributes on the Player. Within the game we should normally use the
|
||||
Player manager's methods to create users so that permissions are set
|
||||
attributes on the Account. Within the game we should normally use the
|
||||
Account manager's methods to create users so that permissions are set
|
||||
correctly.
|
||||
|
||||
To make the Player model more flexible for your own game, it can also
|
||||
To make the Account model more flexible for your own game, it can also
|
||||
persistently store attributes of its own. This is ideal for extra
|
||||
account info and OOC account configuration variables etc.
|
||||
|
||||
|
|
@ -22,11 +22,11 @@ from django.db import models
|
|||
from django.contrib.auth.models import AbstractUser
|
||||
from django.utils.encoding import smart_str
|
||||
|
||||
from evennia.players.manager import PlayerDBManager
|
||||
from evennia.accounts.manager import AccountDBManager
|
||||
from evennia.typeclasses.models import TypedObject
|
||||
from evennia.utils.utils import make_iter
|
||||
|
||||
__all__ = ("PlayerDB",)
|
||||
__all__ = ("AccountDB",)
|
||||
|
||||
#_ME = _("me")
|
||||
#_SELF = _("self")
|
||||
|
|
@ -42,11 +42,11 @@ _TYPECLASS = None
|
|||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# PlayerDB
|
||||
# AccountDB
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
class PlayerDB(TypedObject, AbstractUser):
|
||||
class AccountDB(TypedObject, AbstractUser):
|
||||
"""
|
||||
This is a special model using Django's 'profile' functionality
|
||||
and extends the default Django User model. It is defined as such
|
||||
|
|
@ -66,18 +66,18 @@ class PlayerDB(TypedObject, AbstractUser):
|
|||
- db - persistent attribute storage
|
||||
- ndb - non-persistent attribute storage
|
||||
|
||||
The PlayerDB adds the following properties:
|
||||
The AccountDB adds the following properties:
|
||||
|
||||
- is_connected - If any Session is currently connected to this Player
|
||||
- is_connected - If any Session is currently connected to this Account
|
||||
- name - alias for user.username
|
||||
- sessions - sessions connected to this player
|
||||
- is_superuser - bool if this player is a superuser
|
||||
- is_bot - bool if this player is a bot and not a real player
|
||||
- sessions - sessions connected to this account
|
||||
- is_superuser - bool if this account is a superuser
|
||||
- is_bot - bool if this account is a bot and not a real account
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# PlayerDB Database model setup
|
||||
# AccountDB Database model setup
|
||||
#
|
||||
# inherited fields (from TypedObject):
|
||||
# db_key, db_typeclass_path, db_date_created, db_permissions
|
||||
|
|
@ -90,19 +90,19 @@ class PlayerDB(TypedObject, AbstractUser):
|
|||
# database storage of persistant cmdsets.
|
||||
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
|
||||
help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.")
|
||||
# marks if this is a "virtual" bot player object
|
||||
# marks if this is a "virtual" bot account object
|
||||
db_is_bot = models.BooleanField(default=False, verbose_name="is_bot", help_text="Used to identify irc/rss bots")
|
||||
|
||||
# Database manager
|
||||
objects = PlayerDBManager()
|
||||
objects = AccountDBManager()
|
||||
|
||||
# defaults
|
||||
__settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS
|
||||
__defaultclasspath__ = "evennia.players.players.DefaultPlayer"
|
||||
__applabel__ = "players"
|
||||
__defaultclasspath__ = "evennia.accounts.accounts.DefaultAccount"
|
||||
__applabel__ = "accounts"
|
||||
|
||||
class Meta(object):
|
||||
verbose_name = 'Player'
|
||||
verbose_name = 'Account'
|
||||
|
||||
# cmdset_storage property
|
||||
# This seems very sensitive to caching, so leaving it be for now /Griatch
|
||||
|
|
@ -136,10 +136,10 @@ class PlayerDB(TypedObject, AbstractUser):
|
|||
#
|
||||
|
||||
def __str__(self):
|
||||
return smart_str("%s(player %s)" % (self.name, self.dbid))
|
||||
return smart_str("%s(account %s)" % (self.name, self.dbid))
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s(player#%s)" % (self.name, self.dbid)
|
||||
return u"%s(account#%s)" % (self.name, self.dbid)
|
||||
|
||||
#@property
|
||||
def __username_get(self):
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
This sub-package contains Evennia's command system. It handles
|
||||
everything related to parsing input from the player, building cmdsets
|
||||
everything related to parsing input from the account, building cmdsets
|
||||
and executing the code associated with a found command class.
|
||||
|
||||
commands.default contains all the default "mux-like" commands of
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ command line. The processing of a command works as follows:
|
|||
- object cmdsets: all objects at caller's location are scanned for non-empty
|
||||
cmdsets. This includes cmdsets on exits.
|
||||
- caller: the caller is searched for its own currently active cmdset.
|
||||
- player: lastly the cmdsets defined on caller.player are added.
|
||||
- account: lastly the cmdsets defined on caller.account are added.
|
||||
3. The collected cmdsets are merged together to a combined, current cmdset.
|
||||
4. If the input string is empty -> check for CMD_NOINPUT command in
|
||||
current cmdset or fallback to error message. Exit.
|
||||
|
|
@ -85,7 +85,7 @@ CMD_LOGINSTART = "__unloggedin_look_command"
|
|||
_SEARCH_AT_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
|
||||
# Output strings. The first is the IN_GAME_ERRORS return, the second
|
||||
# is the normal "production message to echo to the player.
|
||||
# is the normal "production message to echo to the account.
|
||||
|
||||
_ERROR_UNTRAPPED = (
|
||||
"""
|
||||
|
|
@ -128,7 +128,7 @@ likely file a bug report with the Evennia project.
|
|||
""")
|
||||
|
||||
_ERROR_RECURSION_LIMIT = "Command recursion limit ({recursion_limit}) " \
|
||||
"reached for '{raw_string}' ({cmdclass})."
|
||||
"reached for '{raw_cmdname}' ({cmdclass})."
|
||||
|
||||
|
||||
# delayed imports
|
||||
|
|
@ -210,7 +210,7 @@ def _process_input(caller, prompt, result, cmd, generator):
|
|||
part of yielding from a Command's `func`.
|
||||
|
||||
Args:
|
||||
caller (Character, Player or Session): the caller.
|
||||
caller (Character, Account or Session): the caller.
|
||||
prompt (basestring): The sent prompt.
|
||||
result (basestring): The unprocessed answer.
|
||||
cmd (Command): The command itself.
|
||||
|
|
@ -248,20 +248,20 @@ class ErrorReported(Exception):
|
|||
# Helper function
|
||||
|
||||
@inlineCallbacks
|
||||
def get_and_merge_cmdsets(caller, session, player, obj, callertype, raw_string):
|
||||
def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string):
|
||||
"""
|
||||
Gather all relevant cmdsets and merge them.
|
||||
|
||||
Args:
|
||||
caller (Session, Player or Object): The entity executing the command. Which
|
||||
caller (Session, Account or Object): The entity executing the command. Which
|
||||
type of object this is depends on the current game state; for example
|
||||
when the user is not logged in, this will be a Session, when being OOC
|
||||
it will be a Player and when puppeting an object this will (often) be
|
||||
it will be an Account and when puppeting an object this will (often) be
|
||||
a Character Object. In the end it depends on where the cmdset is stored.
|
||||
session (Session or None): The Session associated with caller, if any.
|
||||
player (Player or None): The calling Player associated with caller, if any.
|
||||
account (Account or None): The calling Account associated with caller, if any.
|
||||
obj (Object or None): The Object associated with caller, if any.
|
||||
callertype (str): This identifies caller as either "player", "object" or "session"
|
||||
callertype (str): This identifies caller as either "account", "object" or "session"
|
||||
to avoid having to do this check internally.
|
||||
raw_string (str): The input string. This is only used for error reporting.
|
||||
|
||||
|
|
@ -272,18 +272,18 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, raw_string):
|
|||
Notes:
|
||||
The cdmsets are merged in order or generality, so that the
|
||||
Object's cmdset is merged last (and will thus take precedence
|
||||
over same-named and same-prio commands on Player and Session).
|
||||
over same-named and same-prio commands on Account and Session).
|
||||
|
||||
"""
|
||||
try:
|
||||
@inlineCallbacks
|
||||
def _get_channel_cmdset(player_or_obj):
|
||||
def _get_channel_cmdset(account_or_obj):
|
||||
"""
|
||||
Helper-method; Get channel-cmdsets
|
||||
"""
|
||||
# Create cmdset for all player's available channels
|
||||
# Create cmdset for all account's available channels
|
||||
try:
|
||||
channel_cmdset = yield CHANNELHANDLER.get_cmdset(player_or_obj)
|
||||
channel_cmdset = yield CHANNELHANDLER.get_cmdset(account_or_obj)
|
||||
returnValue([channel_cmdset])
|
||||
except Exception:
|
||||
_msg_err(caller, _ERROR_CMDSETS)
|
||||
|
|
@ -313,8 +313,8 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, raw_string):
|
|||
_GA(lobj, "at_cmdset_get")(caller=caller)
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
# the call-type lock is checked here, it makes sure a player
|
||||
# is not seeing e.g. the commands on a fellow player (which is why
|
||||
# the call-type lock is checked here, it makes sure an account
|
||||
# is not seeing e.g. the commands on a fellow account (which is why
|
||||
# the no_superuser_bypass must be True)
|
||||
local_obj_cmdsets = \
|
||||
yield list(chain.from_iterable(
|
||||
|
|
@ -355,9 +355,9 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, raw_string):
|
|||
# we are calling the command from the session level
|
||||
report_to = session
|
||||
current, cmdsets = yield _get_cmdsets(session)
|
||||
if player: # this automatically implies logged-in
|
||||
pcurrent, player_cmdsets = yield _get_cmdsets(player)
|
||||
cmdsets += player_cmdsets
|
||||
if account: # this automatically implies logged-in
|
||||
pcurrent, account_cmdsets = yield _get_cmdsets(account)
|
||||
cmdsets += account_cmdsets
|
||||
current = current + pcurrent
|
||||
if obj:
|
||||
ocurrent, obj_cmdsets = yield _get_cmdsets(obj)
|
||||
|
|
@ -374,13 +374,13 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, raw_string):
|
|||
channel_cmdsets = yield _get_channel_cmdset(obj)
|
||||
cmdsets += channel_cmdsets
|
||||
if not current.no_channels:
|
||||
channel_cmdsets = yield _get_channel_cmdset(player)
|
||||
channel_cmdsets = yield _get_channel_cmdset(account)
|
||||
cmdsets += channel_cmdsets
|
||||
|
||||
elif callertype == "player":
|
||||
# we are calling the command from the player level
|
||||
report_to = player
|
||||
current, cmdsets = yield _get_cmdsets(player)
|
||||
elif callertype == "account":
|
||||
# we are calling the command from the account level
|
||||
report_to = account
|
||||
current, cmdsets = yield _get_cmdsets(account)
|
||||
if obj:
|
||||
ocurrent, obj_cmdsets = yield _get_cmdsets(obj)
|
||||
current = current + ocurrent
|
||||
|
|
@ -395,7 +395,7 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, raw_string):
|
|||
# also objs may have channels
|
||||
cmdsets += yield _get_channel_cmdset(obj)
|
||||
if not current.no_channels:
|
||||
cmdsets += yield _get_channel_cmdset(player)
|
||||
cmdsets += yield _get_channel_cmdset(account)
|
||||
|
||||
elif callertype == "object":
|
||||
# we are calling the command from the object level
|
||||
|
|
@ -472,22 +472,22 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
This is the main mechanism that handles any string sent to the engine.
|
||||
|
||||
Args:
|
||||
called_by (Session, Player or Object): Object from which this
|
||||
called_by (Session, Account or Object): Object from which this
|
||||
command was called. which this was called from. What this is
|
||||
depends on the game state.
|
||||
raw_string (str): The command string as given on the command line.
|
||||
_testing (bool, optional): Used for debug purposes and decides if we
|
||||
should actually execute the command or not. If True, the
|
||||
command instance will be returned.
|
||||
callertype (str, optional): One of "session", "player" or
|
||||
callertype (str, optional): One of "session", "account" or
|
||||
"object". These are treated in decending order, so when the
|
||||
Session is the caller, it will merge its own cmdset into
|
||||
cmdsets from both Player and eventual puppeted Object (and
|
||||
cmdsets in its room etc). A Player will only include its own
|
||||
cmdsets from both Account and eventual puppeted Object (and
|
||||
cmdsets in its room etc). An Account will only include its own
|
||||
cmdset and the Objects and so on. Merge order is the same
|
||||
order, so that Object cmdsets are merged in last, giving them
|
||||
precendence for same-name and same-prio commands.
|
||||
session (Session, optional): Relevant if callertype is "player" - the session will help
|
||||
session (Session, optional): Relevant if callertype is "account" - the session will help
|
||||
retrieve the correct cmdsets from puppeted objects.
|
||||
cmdobj (Command, optional): If given a command instance, this will be executed using
|
||||
`called_by` as the caller, `raw_string` representing its arguments and (optionally)
|
||||
|
|
@ -513,20 +513,22 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
"""
|
||||
|
||||
@inlineCallbacks
|
||||
def _run_command(cmd, cmdname, args, raw_string, cmdset, session, player):
|
||||
def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account):
|
||||
"""
|
||||
Helper function: This initializes and runs the Command
|
||||
instance once the parser has identified it as either a normal
|
||||
command or one of the system commands.
|
||||
|
||||
Args:
|
||||
cmd (Command): Command object.
|
||||
cmdname (str): Name of command.
|
||||
args (str): Extra text entered after the identified command.
|
||||
raw_string (str): Full input string.
|
||||
cmd (Command): Command object
|
||||
cmdname (str): Name of command
|
||||
args (str): extra text entered after the identified command
|
||||
raw_cmdname (str): Name of Command, unaffected by eventual
|
||||
prefix-stripping (if no prefix-stripping, this is the same
|
||||
as cmdname).
|
||||
cmdset (CmdSet): Command sert the command belongs to (if any)..
|
||||
session (Session): Session of caller (if any).
|
||||
player (Player): Player of caller (if any).
|
||||
account (Account): Account of caller (if any).
|
||||
|
||||
Returns:
|
||||
deferred (Deferred): this will fire with the return of the
|
||||
|
|
@ -540,12 +542,14 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
try:
|
||||
# Assign useful variables to the instance
|
||||
cmd.caller = caller
|
||||
cmd.cmdstring = cmdname
|
||||
cmd.cmdname = cmdname
|
||||
cmd.raw_cmdname = raw_cmdname
|
||||
cmd.cmdstring = cmdname # deprecated
|
||||
cmd.args = args
|
||||
cmd.cmdset = cmdset
|
||||
cmd.session = session
|
||||
cmd.player = player
|
||||
cmd.raw_string = raw_string
|
||||
cmd.account = account
|
||||
cmd.raw_string = unformatted_raw_string
|
||||
#cmd.obj # set via on-object cmdset handler for each command,
|
||||
# since this may be different for every command when
|
||||
# merging multuple cmdsets
|
||||
|
|
@ -566,7 +570,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
_COMMAND_NESTING[called_by] += 1
|
||||
if _COMMAND_NESTING[called_by] > _COMMAND_RECURSION_LIMIT:
|
||||
err = _ERROR_RECURSION_LIMIT.format(recursion_limit=_COMMAND_RECURSION_LIMIT,
|
||||
raw_string=raw_string,
|
||||
raw_cmdname=raw_cmdname,
|
||||
cmdclass=cmd.__class__)
|
||||
raise RuntimeError(err)
|
||||
|
||||
|
|
@ -614,13 +618,13 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
|
||||
raw_string = to_unicode(raw_string, force_string=True)
|
||||
|
||||
session, player, obj = session, None, None
|
||||
session, account, obj = session, None, None
|
||||
if callertype == "session":
|
||||
session = called_by
|
||||
player = session.player
|
||||
account = session.account
|
||||
obj = session.puppet
|
||||
elif callertype == "player":
|
||||
player = called_by
|
||||
elif callertype == "account":
|
||||
account = called_by
|
||||
if session:
|
||||
obj = yield session.puppet
|
||||
elif callertype == "object":
|
||||
|
|
@ -629,32 +633,32 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
raise RuntimeError("cmdhandler: callertype %s is not valid." % callertype)
|
||||
# the caller will be the one to receive messages and excert its permissions.
|
||||
# we assign the caller with preference 'bottom up'
|
||||
caller = obj or player or session
|
||||
# The error_to is the default recipient for errors. Tries to make sure a player
|
||||
caller = obj or account or session
|
||||
# The error_to is the default recipient for errors. Tries to make sure an account
|
||||
# does not get spammed for errors while preserving character mirroring.
|
||||
error_to = obj or session or player
|
||||
error_to = obj or session or account
|
||||
|
||||
try: # catch bugs in cmdhandler itself
|
||||
try: # catch special-type commands
|
||||
if cmdobj:
|
||||
# the command object is already given
|
||||
|
||||
cmd = cmdobj() if callable(cmdobj) else cmdobj
|
||||
cmdname = cmdobj_key if cmdobj_key else cmd.key
|
||||
args = raw_string
|
||||
unformatted_raw_string = "%s%s" % (cmdname, args)
|
||||
cmdset = None
|
||||
session = session
|
||||
player = player
|
||||
account = account
|
||||
|
||||
else:
|
||||
# no explicit cmdobject given, figure it out
|
||||
|
||||
cmdset = yield get_and_merge_cmdsets(caller, session, player, obj,
|
||||
cmdset = yield get_and_merge_cmdsets(caller, session, account, obj,
|
||||
callertype, raw_string)
|
||||
if not cmdset:
|
||||
# this is bad and shouldn't happen.
|
||||
raise NoCmdSets
|
||||
# store the completely unmodified raw string - including
|
||||
# whitespace and eventual prefixes-to-be-stripped.
|
||||
unformatted_raw_string = raw_string
|
||||
raw_string = raw_string.strip()
|
||||
if not raw_string:
|
||||
|
|
@ -685,7 +689,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
if len(matches) == 1:
|
||||
# We have a unique command match. But it may still be invalid.
|
||||
match = matches[0]
|
||||
cmdname, args, cmd = match[0], match[1], match[2]
|
||||
cmdname, args, cmd, raw_cmdname = match[0], match[1], match[2], match[5]
|
||||
|
||||
if not matches:
|
||||
# No commands match our entered command
|
||||
|
|
@ -718,7 +722,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
raise ExecSystemCommand(cmd, sysarg)
|
||||
|
||||
# A normal command.
|
||||
ret = yield _run_command(cmd, cmdname, args, unformatted_raw_string, cmdset, session, player)
|
||||
ret = yield _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account)
|
||||
returnValue(ret)
|
||||
|
||||
except ErrorReported as exc:
|
||||
|
|
@ -734,7 +738,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
|||
|
||||
if syscmd:
|
||||
ret = yield _run_command(syscmd, syscmd.key, sysarg,
|
||||
unformatted_raw_string, cmdset, session, player)
|
||||
unformatted_raw_string, cmdset, session, account)
|
||||
returnValue(ret)
|
||||
elif sysarg:
|
||||
# return system arg
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from django.conf import settings
|
|||
from evennia.utils.logger import log_trace
|
||||
|
||||
_MULTIMATCH_REGEX = re.compile(settings.SEARCH_MULTIMATCH_REGEX, re.I + re.U)
|
||||
_CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
|
||||
|
||||
def cmdparser(raw_string, cmdset, caller, match_index=None):
|
||||
"""
|
||||
|
|
@ -21,7 +22,7 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
Args:
|
||||
raw_string (str): The unparsed text entered by the caller.
|
||||
cmdset (CmdSet): The merged, currently valid cmdset
|
||||
caller (Session, Player or Object): The caller triggering this parsing.
|
||||
caller (Session, Account or Object): The caller triggering this parsing.
|
||||
match_index (int, optional): Index to pick a given match in a
|
||||
list of same-named command matches. If this is given, it suggests
|
||||
this is not the first time this function was called: normally
|
||||
|
|
@ -46,7 +47,7 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
|
||||
"""
|
||||
|
||||
def create_match(cmdname, string, cmdobj):
|
||||
def create_match(cmdname, string, cmdobj, raw_cmdname):
|
||||
"""
|
||||
Builds a command match by splitting the incoming string and
|
||||
evaluating the quality of the match.
|
||||
|
|
@ -55,51 +56,79 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
cmdname (str): Name of command to check for.
|
||||
string (str): The string to match against.
|
||||
cmdobj (str): The full Command instance.
|
||||
raw_cmdname (str, optional): If CMD_IGNORE_PREFIX is set and the cmdname starts with
|
||||
one of the prefixes to ignore, this contains the raw, unstripped cmdname,
|
||||
otherwise it is None.
|
||||
|
||||
Returns:
|
||||
match (tuple): This is on the form (cmdname, args, cmdobj, cmdlen, mratio), where
|
||||
match (tuple): This is on the form (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname), where
|
||||
`cmdname` is the command's name and `args` the rest of the incoming string,
|
||||
without said command name. `cmdobj` is the Command instance, the cmdlen is
|
||||
the same as len(cmdname) and mratio is a measure of how big a part of the
|
||||
full input string the cmdname takes up - an exact match would be 1.0.
|
||||
full input string the cmdname takes up - an exact match would be 1.0. Finally,
|
||||
the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping.
|
||||
|
||||
"""
|
||||
cmdlen, strlen = len(unicode(cmdname)), len(unicode(string))
|
||||
mratio = 1 - (strlen - cmdlen) / (1.0 * strlen)
|
||||
args = string[cmdlen:]
|
||||
return (cmdname, args, cmdobj, cmdlen, mratio)
|
||||
return (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname)
|
||||
|
||||
def build_matches(raw_string, include_prefixes=False):
|
||||
l_raw_string = raw_string.lower()
|
||||
matches = []
|
||||
try:
|
||||
if include_prefixes:
|
||||
# use the cmdname as-is
|
||||
for cmd in cmdset:
|
||||
matches.extend([create_match(cmdname, raw_string, cmd, cmdname)
|
||||
for cmdname in [cmd.key] + cmd.aliases
|
||||
if cmdname and l_raw_string.startswith(cmdname.lower())
|
||||
and (not cmd.arg_regex or
|
||||
cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
|
||||
else:
|
||||
# strip prefixes set in settings
|
||||
for cmd in cmdset:
|
||||
for raw_cmdname in [cmd.key] + cmd.aliases:
|
||||
cmdname = raw_cmdname.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_cmdname) > 1 else raw_cmdname
|
||||
if cmdname and l_raw_string.startswith(cmdname.lower()) and \
|
||||
(not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])):
|
||||
matches.append(create_match(cmdname, raw_string, cmd, raw_cmdname))
|
||||
except Exception:
|
||||
log_trace("cmdhandler error. raw_input:%s" % raw_string)
|
||||
return matches
|
||||
|
||||
def try_num_prefixes(raw_string):
|
||||
if not matches:
|
||||
# no matches found
|
||||
num_ref_match = _MULTIMATCH_REGEX.match(raw_string)
|
||||
if num_ref_match:
|
||||
# the user might be trying to identify the command
|
||||
# with a #num-command style syntax. We expect the regex to
|
||||
# contain the groups "number" and "name".
|
||||
mindex, new_raw_string = num_ref_match.group("number"), num_ref_match.group("name")
|
||||
return mindex, new_raw_string
|
||||
return None, None
|
||||
|
||||
if not raw_string:
|
||||
return []
|
||||
|
||||
matches = []
|
||||
|
||||
# match everything that begins with a matching cmdname.
|
||||
l_raw_string = raw_string.lower()
|
||||
for cmd in cmdset:
|
||||
try:
|
||||
matches.extend([create_match(cmdname, raw_string, cmd)
|
||||
for cmdname in [cmd.key] + cmd.aliases
|
||||
if cmdname and l_raw_string.startswith(cmdname.lower())
|
||||
and (not cmd.arg_regex or
|
||||
cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
|
||||
except Exception:
|
||||
log_trace("cmdhandler error. raw_input:%s" % raw_string)
|
||||
|
||||
# find mathces, first using the full name
|
||||
matches = build_matches(raw_string, include_prefixes=True)
|
||||
if not matches:
|
||||
# no matches found
|
||||
num_ref_match = _MULTIMATCH_REGEX.match(raw_string)
|
||||
if num_ref_match:
|
||||
# the user might be trying to identify the command
|
||||
# with a #num-command style syntax. We expect the regex to
|
||||
# contain the groups "number" and "name".
|
||||
mindex, new_raw_string = num_ref_match.group("number"), num_ref_match.group("name")
|
||||
return cmdparser(new_raw_string, cmdset,
|
||||
caller, match_index=int(mindex))
|
||||
# try to match a number 1-cmdname, 2-cmdname etc
|
||||
mindex, new_raw_string = try_num_prefixes(raw_string)
|
||||
if mindex is not None:
|
||||
return cmdparser(new_raw_string, cmdset, caller, match_index=int(mindex))
|
||||
if _CMD_IGNORE_PREFIXES:
|
||||
# still no match. Try to strip prefixes
|
||||
raw_string = raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string
|
||||
matches = build_matches(raw_string, include_prefixes=False)
|
||||
|
||||
# only select command matches we are actually allowed to call.
|
||||
matches = [match for match in matches if match[2].access(caller, 'cmd')]
|
||||
|
||||
# try to bring the number of matches down to 1
|
||||
if len(matches) > 1:
|
||||
# See if it helps to analyze the match with preserved case but only if
|
||||
# it leaves at least one match.
|
||||
|
|
@ -129,4 +158,3 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
|
||||
# no matter what we have at this point, we have to return it.
|
||||
return matches
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ A Command Set (CmdSet) holds a set of commands. The Cmdsets can be
|
|||
merged and combined to create new sets of commands in a
|
||||
non-destructive way. This makes them very powerful for implementing
|
||||
custom game states where different commands (or different variations
|
||||
of commands) are available to the players depending on circumstance.
|
||||
of commands) are available to the accounts depending on circumstance.
|
||||
|
||||
The available merge operations are partly borrowed from mathematical
|
||||
Set theory.
|
||||
|
|
@ -110,9 +110,9 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
|
|||
merger (i.e. A above) automatically taking
|
||||
precedence. But if allow_duplicates is true, the
|
||||
result will be a merger with more than one of each
|
||||
name match. This will usually lead to the player
|
||||
name match. This will usually lead to the account
|
||||
receiving a multiple-match error higher up the road,
|
||||
but can be good for things like cmdsets on non-player
|
||||
but can be good for things like cmdsets on non-account
|
||||
objects in a room, to allow the system to warn that
|
||||
more than one 'ball' in the room has the same 'kick'
|
||||
command defined on it, so it may offer a chance to
|
||||
|
|
@ -134,7 +134,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
|
|||
commands
|
||||
no_channels - ignore the name of channels when matching against
|
||||
commands (WARNING- this is dangerous since the
|
||||
player can then not even ask staff for help if
|
||||
account can then not even ask staff for help if
|
||||
something goes wrong)
|
||||
|
||||
|
||||
|
|
@ -167,9 +167,9 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
|
|||
Creates a new CmdSet instance.
|
||||
|
||||
Args:
|
||||
cmdsetobj (Session, Player, Object, optional): This is the database object
|
||||
cmdsetobj (Session, Account, Object, optional): This is the database object
|
||||
to which this particular instance of cmdset is related. It
|
||||
is often a character but may also be a regular object, Player
|
||||
is often a character but may also be a regular object, Account
|
||||
or Session.
|
||||
key (str, optional): The idenfier for this cmdset. This
|
||||
helps if wanting to selectively remov cmdsets.
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ intelligent container that, when added to other CmdSet make sure that
|
|||
same-name commands are treated correctly (usually so there are no
|
||||
doublets). This temporary but up-to-date merger of CmdSet is jointly
|
||||
called the Current Cmset. It is this Current CmdSet that the
|
||||
commandhandler looks through whenever a player enters a command (it
|
||||
also adds CmdSets from objects in the room in real-time). All player
|
||||
commandhandler looks through whenever an account enters a command (it
|
||||
also adds CmdSets from objects in the room in real-time). All account
|
||||
objects have a 'default cmdset' containing all the normal in-game mud
|
||||
commands (look etc).
|
||||
|
||||
|
|
@ -19,12 +19,12 @@ So what is all this cmdset complexity good for?
|
|||
In its simplest form, a CmdSet has no commands, only a key name. In
|
||||
this case the cmdset's use is up to each individual game - it can be
|
||||
used by an AI module for example (mobs in cmdset 'roam' move from room
|
||||
to room, in cmdset 'attack' they enter combat with players).
|
||||
to room, in cmdset 'attack' they enter combat with accounts).
|
||||
|
||||
Defining commands in cmdsets offer some further powerful game-design
|
||||
consequences however. Here are some examples:
|
||||
|
||||
As mentioned above, all players always have at least the Default
|
||||
As mentioned above, all accounts always have at least the Default
|
||||
CmdSet. This contains the set of all normal-use commands in-game,
|
||||
stuff like look and @desc etc. Now assume our players end up in a dark
|
||||
room. You don't want the player to be able to do much in that dark
|
||||
|
|
@ -37,7 +37,7 @@ and have this completely replace the default cmdset.
|
|||
|
||||
Another example: Say you want your players to be able to go
|
||||
fishing. You could implement this as a 'fish' command that fails
|
||||
whenever the player has no fishing rod. Easy enough. But what if you
|
||||
whenever the account has no fishing rod. Easy enough. But what if you
|
||||
want to make fishing more complex - maybe you want four-five different
|
||||
commands for throwing your line, reeling in, etc? Most players won't
|
||||
(we assume) have fishing gear, and having all those detailed commands
|
||||
|
|
@ -48,7 +48,7 @@ for a minor thing like fishing?
|
|||
So instead you put all those detailed fishing commands into their own
|
||||
CommandSet called 'Fishing'. Whenever the player gives the command
|
||||
'fish' (presumably the code checks there is also water nearby), only
|
||||
THEN this CommandSet is added to the Cmdhandler of the player. The
|
||||
THEN this CommandSet is added to the Cmdhandler of the account. The
|
||||
'throw' command (which normally throws rocks) is replaced by the
|
||||
custom 'fishing variant' of throw. What has happened is that the
|
||||
Fishing CommandSet was merged on top of the Default ones, and due to
|
||||
|
|
@ -128,7 +128,7 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
|||
Args:
|
||||
path (str): The path to the command set to load.
|
||||
cmdsetobj (CmdSet): The database object/typeclass on which this cmdset is to be
|
||||
assigned (this can be also channels and exits, as well as players
|
||||
assigned (this can be also channels and exits, as well as accounts
|
||||
but there will always be such an object)
|
||||
emit_to_obj (Object, optional): If given, error is emitted to
|
||||
this object (in addition to logging)
|
||||
|
|
|
|||
|
|
@ -152,14 +152,14 @@ class Command(with_metaclass(CommandMeta, object)):
|
|||
is_exit = False
|
||||
# define the command not only by key but by the regex form of its arguments
|
||||
arg_regex = settings.COMMAND_DEFAULT_ARG_REGEX
|
||||
# whether self.msg sends to all sessions of a related player/object (default
|
||||
# whether self.msg sends to all sessions of a related account/object (default
|
||||
# is to only send to the session sending the command).
|
||||
msg_all_sessions = settings.COMMAND_DEFAULT_MSG_ALL_SESSIONS
|
||||
|
||||
# auto-set (by Evennia on command instantiation) are:
|
||||
# obj - which object this command is defined on
|
||||
# session - which session is responsible for triggering this command. Only set
|
||||
# if triggered by a player.
|
||||
# if triggered by an account.
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
|
|
@ -307,7 +307,7 @@ class Command(with_metaclass(CommandMeta, object)):
|
|||
session=None, **kwargs):
|
||||
"""
|
||||
This is a shortcut instead of calling msg() directly on an
|
||||
object - it will detect if caller is an Object or a Player and
|
||||
object - it will detect if caller is an Object or an Account and
|
||||
also appends self.session automatically if self.msg_all_sessions is False.
|
||||
|
||||
Args:
|
||||
|
|
@ -340,7 +340,7 @@ class Command(with_metaclass(CommandMeta, object)):
|
|||
Args:
|
||||
raw_string (str): Execute this string as a command input.
|
||||
session (Session, optional): If not given, the current command's Session will be used.
|
||||
obj (Object or Player, optional): Object or Player on which to call the execute_cmd.
|
||||
obj (Object or Account, optional): Object or Account on which to call the execute_cmd.
|
||||
If not given, self.caller will be used.
|
||||
|
||||
Kwargs:
|
||||
|
|
@ -443,7 +443,7 @@ class Command(with_metaclass(CommandMeta, object)):
|
|||
commands the caller can use.
|
||||
|
||||
Args:
|
||||
caller (Object or Player): the caller asking for help on the command.
|
||||
caller (Object or Account): the caller asking for help on the command.
|
||||
cmdset (CmdSet): the command set (if you need additional commands).
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
"""
|
||||
Player (OOC) commands. These are stored on the Player object
|
||||
and self.caller is thus always a Player, not an Object/Character.
|
||||
Account (OOC) commands. These are stored on the Account object
|
||||
and self.caller is thus always an Account, not an Object/Character.
|
||||
|
||||
These commands go in the PlayerCmdset and are accessible also
|
||||
These commands go in the AccountCmdset and are accessible also
|
||||
when puppeting a Character (although with lower priority)
|
||||
|
||||
These commands use the player_caller property which tells the command
|
||||
These commands use the account_caller property which tells the command
|
||||
parent (MuxCommand, usually) to setup caller correctly. They use
|
||||
self.player to make sure to always use the player object rather than
|
||||
self.account to make sure to always use the account object rather than
|
||||
self.caller (which change depending on the level you are calling from)
|
||||
The property self.character can be used to access the character when
|
||||
these commands are triggered with a connected character (such as the
|
||||
case of the @ooc command), it is None if we are OOC.
|
||||
|
||||
Note that under MULTISESSION_MODE > 2, Player commands should use
|
||||
Note that under MULTISESSION_MODE > 2, Account commands should use
|
||||
self.msg() and similar methods to reroute returns to the correct
|
||||
method. Otherwise all text will be returned to all connected sessions.
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ __all__ = ("CmdOOCLook", "CmdIC", "CmdOOC", "CmdPassword", "CmdQuit",
|
|||
"CmdColorTest", "CmdQuell")
|
||||
|
||||
|
||||
class MuxPlayerLookCommand(COMMAND_DEFAULT_CLASS):
|
||||
class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
Custom parent (only) parsing for OOC looking, sets a "playable"
|
||||
property on the command based on the parsing.
|
||||
|
|
@ -46,19 +46,19 @@ class MuxPlayerLookCommand(COMMAND_DEFAULT_CLASS):
|
|||
def parse(self):
|
||||
"""Custom parsing"""
|
||||
|
||||
super(MuxPlayerLookCommand, self).parse()
|
||||
super(MuxAccountLookCommand, self).parse()
|
||||
|
||||
if _MULTISESSION_MODE < 2:
|
||||
# only one character allowed - not used in this mode
|
||||
self.playable = None
|
||||
return
|
||||
|
||||
playable = self.player.db._playable_characters
|
||||
playable = self.account.db._playable_characters
|
||||
if playable is not None:
|
||||
# clean up list if character object was deleted in between
|
||||
if None in playable:
|
||||
playable = [character for character in playable if character]
|
||||
self.player.db._playable_characters = playable
|
||||
self.account.db._playable_characters = playable
|
||||
# store playable property
|
||||
if self.args:
|
||||
self.playable = dict((utils.to_str(char.key.lower()), char)
|
||||
|
|
@ -67,13 +67,13 @@ class MuxPlayerLookCommand(COMMAND_DEFAULT_CLASS):
|
|||
self.playable = playable
|
||||
|
||||
|
||||
# Obs - these are all intended to be stored on the Player, and as such,
|
||||
# use self.player instead of self.caller, just to be sure. Also self.msg()
|
||||
# Obs - these are all intended to be stored on the Account, and as such,
|
||||
# use self.account instead of self.caller, just to be sure. Also self.msg()
|
||||
# is used to make sure returns go to the right session
|
||||
|
||||
# note that this is inheriting from MuxPlayerLookCommand,
|
||||
# note that this is inheriting from MuxAccountLookCommand,
|
||||
# and has the .playable property.
|
||||
class CmdOOCLook(MuxPlayerLookCommand):
|
||||
class CmdOOCLook(MuxAccountLookCommand):
|
||||
"""
|
||||
look while out-of-character
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ class CmdOOCLook(MuxPlayerLookCommand):
|
|||
"""
|
||||
|
||||
# This is an OOC version of the look command. Since a
|
||||
# Player doesn't have an in-game existence, there is no
|
||||
# Account 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.
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ class CmdOOCLook(MuxPlayerLookCommand):
|
|||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""implement the ooc look command"""
|
||||
|
|
@ -104,8 +104,8 @@ class CmdOOCLook(MuxPlayerLookCommand):
|
|||
self.msg("You are out-of-character (OOC).\nUse |w@ic|n to get back into the game.")
|
||||
return
|
||||
|
||||
# call on-player look helper method
|
||||
self.msg(self.player.at_look(target=self.playable, session=self.session))
|
||||
# call on-account look helper method
|
||||
self.msg(self.account.at_look(target=self.playable, session=self.session))
|
||||
|
||||
|
||||
class CmdCharCreate(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -121,15 +121,15 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
|
|||
if you want.
|
||||
"""
|
||||
key = "@charcreate"
|
||||
locks = "cmd:pperm(Players)"
|
||||
locks = "cmd:pperm(Account)"
|
||||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""create the new character"""
|
||||
player = self.player
|
||||
account = self.account
|
||||
if not self.args:
|
||||
self.msg("Usage: @charcreate <charname> [= description]")
|
||||
return
|
||||
|
|
@ -138,9 +138,9 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
charmax = _MAX_NR_CHARACTERS if _MULTISESSION_MODE > 1 else 1
|
||||
|
||||
if not player.is_superuser and \
|
||||
(player.db._playable_characters and
|
||||
len(player.db._playable_characters) >= charmax):
|
||||
if not account.is_superuser and \
|
||||
(account.db._playable_characters and
|
||||
len(account.db._playable_characters) >= charmax):
|
||||
self.msg("You may only create a maximum of %i characters." % charmax)
|
||||
return
|
||||
from evennia.objects.models import ObjectDB
|
||||
|
|
@ -156,19 +156,19 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
|
|||
# create the character
|
||||
start_location = ObjectDB.objects.get_id(settings.START_LOCATION)
|
||||
default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
|
||||
new_character = create.create_object(typeclass, key=key,
|
||||
location=start_location,
|
||||
home=default_home,
|
||||
permissions=permissions)
|
||||
# only allow creator (and immortals) to puppet this char
|
||||
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
|
||||
(new_character.id, player.id))
|
||||
player.db._playable_characters.append(new_character)
|
||||
# only allow creator (and developers) to puppet this char
|
||||
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)" %
|
||||
(new_character.id, account.id))
|
||||
account.db._playable_characters.append(new_character)
|
||||
if desc:
|
||||
new_character.db.desc = desc
|
||||
elif not new_character.db.desc:
|
||||
new_character.db.desc = "This is a Player."
|
||||
new_character.db.desc = "This is an Account."
|
||||
self.msg("Created new character %s. Use |w@ic %s|n to enter the game as this character."
|
||||
% (new_character.key, new_character.key))
|
||||
|
||||
|
|
@ -183,19 +183,19 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
|
|||
Permanently deletes one of your characters.
|
||||
"""
|
||||
key = "@chardelete"
|
||||
locks = "cmd:pperm(Players)"
|
||||
locks = "cmd:pperm(Account)"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"""delete the character"""
|
||||
player = self.player
|
||||
account = self.account
|
||||
|
||||
if not self.args:
|
||||
self.msg("Usage: @chardelete <charactername>")
|
||||
return
|
||||
|
||||
# use the playable_characters list to search
|
||||
match = [char for char in utils.make_iter(player.db._playable_characters)
|
||||
match = [char for char in utils.make_iter(account.db._playable_characters)
|
||||
if char.key.lower() == self.args.lower()]
|
||||
if not match:
|
||||
self.msg("You have no such character to delete.")
|
||||
|
|
@ -219,9 +219,9 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
|
|||
del caller.ndb._char_to_delete
|
||||
|
||||
match = match[0]
|
||||
player.ndb._char_to_delete = match
|
||||
account.ndb._char_to_delete = match
|
||||
prompt = "|rThis will permanently destroy '%s'. This cannot be undone.|n Continue yes/[no]?"
|
||||
get_input(player, prompt % match.key, _callback)
|
||||
get_input(account, prompt % match.key, _callback)
|
||||
|
||||
|
||||
class CmdIC(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -234,12 +234,12 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
|||
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
|
||||
the right to do so. Note that it's the ACCOUNT 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.
|
||||
account. In principle <character> can be any in-game object as long
|
||||
as you the account have access right to puppet it.
|
||||
"""
|
||||
|
||||
key = "@ic"
|
||||
|
|
@ -249,24 +249,24 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
Main puppet method
|
||||
"""
|
||||
player = self.player
|
||||
account = self.account
|
||||
session = self.session
|
||||
|
||||
new_character = None
|
||||
if not self.args:
|
||||
new_character = player.db._last_puppet
|
||||
new_character = account.db._last_puppet
|
||||
if not new_character:
|
||||
self.msg("Usage: @ic <character>")
|
||||
return
|
||||
if not new_character:
|
||||
# search for a matching character
|
||||
new_character = [char for char in search.object_search(self.args) if char.access(player, "puppet")]
|
||||
new_character = [char for char in search.object_search(self.args) if char.access(account, "puppet")]
|
||||
if not new_character:
|
||||
self.msg("That is not a valid character choice.")
|
||||
return
|
||||
|
|
@ -277,15 +277,15 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
|||
else:
|
||||
new_character = new_character[0]
|
||||
try:
|
||||
player.puppet_object(session, new_character)
|
||||
player.db._last_puppet = new_character
|
||||
account.puppet_object(session, new_character)
|
||||
account.db._last_puppet = new_character
|
||||
except RuntimeError as exc:
|
||||
self.msg("|rYou cannot become |C%s|n: %s" % (new_character.name, exc))
|
||||
|
||||
|
||||
# note that this is inheriting from MuxPlayerLookCommand,
|
||||
# note that this is inheriting from MuxAccountLookCommand,
|
||||
# and as such has the .playable property.
|
||||
class CmdOOC(MuxPlayerLookCommand):
|
||||
class CmdOOC(MuxAccountLookCommand):
|
||||
"""
|
||||
stop puppeting and go ooc
|
||||
|
||||
|
|
@ -298,30 +298,30 @@ class CmdOOC(MuxPlayerLookCommand):
|
|||
"""
|
||||
|
||||
key = "@ooc"
|
||||
locks = "cmd:pperm(Players)"
|
||||
locks = "cmd:pperm(Account)"
|
||||
aliases = "@unpuppet"
|
||||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement function"""
|
||||
|
||||
player = self.player
|
||||
account = self.account
|
||||
session = self.session
|
||||
|
||||
old_char = player.get_puppet(session)
|
||||
old_char = account.get_puppet(session)
|
||||
if not old_char:
|
||||
string = "You are already OOC."
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
player.db._last_puppet = old_char
|
||||
account.db._last_puppet = old_char
|
||||
|
||||
# disconnect
|
||||
try:
|
||||
player.unpuppet_object(session)
|
||||
account.unpuppet_object(session)
|
||||
self.msg("\n|GYou go OOC.|n\n")
|
||||
|
||||
if _MULTISESSION_MODE < 2:
|
||||
|
|
@ -329,7 +329,7 @@ class CmdOOC(MuxPlayerLookCommand):
|
|||
self.msg("You are out-of-character (OOC).\nUse |w@ic|n to get back into the game.")
|
||||
return
|
||||
|
||||
self.msg(player.at_look(target=self.playable, session=session))
|
||||
self.msg(account.at_look(target=self.playable, session=session))
|
||||
|
||||
except RuntimeError as exc:
|
||||
self.msg("|rCould not unpuppet from |c%s|n: %s" % (old_char, exc))
|
||||
|
|
@ -350,19 +350,19 @@ class CmdSessions(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement function"""
|
||||
player = self.player
|
||||
sessions = player.sessions.all()
|
||||
account = self.account
|
||||
sessions = account.sessions.all()
|
||||
table = evtable.EvTable("|wsessid",
|
||||
"|wprotocol",
|
||||
"|whost",
|
||||
"|wpuppet/character",
|
||||
"|wlocation")
|
||||
for sess in sorted(sessions, key=lambda x: x.sessid):
|
||||
char = player.get_puppet(sess)
|
||||
char = account.get_puppet(sess)
|
||||
table.add_row(str(sess.sessid), str(sess.protocol_key),
|
||||
type(sess.address) == tuple and sess.address[0] or sess.address,
|
||||
char and str(char) or "None",
|
||||
|
|
@ -387,27 +387,27 @@ class CmdWho(COMMAND_DEFAULT_CLASS):
|
|||
locks = "cmd:all()"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
Get all connected players by polling session.
|
||||
Get all connected accounts by polling session.
|
||||
"""
|
||||
|
||||
player = self.player
|
||||
account = self.account
|
||||
session_list = SESSIONS.get_sessions()
|
||||
|
||||
session_list = sorted(session_list, key=lambda o: o.player.key)
|
||||
session_list = sorted(session_list, key=lambda o: o.account.key)
|
||||
|
||||
if self.cmdstring == "doing":
|
||||
show_session_data = False
|
||||
else:
|
||||
show_session_data = player.check_permstring("Immortals") or player.check_permstring("Wizards")
|
||||
show_session_data = account.check_permstring("Developer") or account.check_permstring("Admins")
|
||||
|
||||
nplayers = (SESSIONS.player_count())
|
||||
naccounts = (SESSIONS.account_count())
|
||||
if show_session_data:
|
||||
# privileged info
|
||||
table = evtable.EvTable("|wPlayer Name",
|
||||
table = evtable.EvTable("|wAccount Name",
|
||||
"|wOn for",
|
||||
"|wIdle",
|
||||
"|wPuppeting",
|
||||
|
|
@ -420,10 +420,10 @@ class CmdWho(COMMAND_DEFAULT_CLASS):
|
|||
continue
|
||||
delta_cmd = time.time() - session.cmd_last_visible
|
||||
delta_conn = time.time() - session.conn_time
|
||||
player = session.get_player()
|
||||
account = session.get_account()
|
||||
puppet = session.get_puppet()
|
||||
location = puppet.location.key if puppet and puppet.location else "None"
|
||||
table.add_row(utils.crop(player.name, width=25),
|
||||
table.add_row(utils.crop(account.name, width=25),
|
||||
utils.time_format(delta_conn, 0),
|
||||
utils.time_format(delta_cmd, 1),
|
||||
utils.crop(puppet.key if puppet else "None", width=25),
|
||||
|
|
@ -433,19 +433,19 @@ class CmdWho(COMMAND_DEFAULT_CLASS):
|
|||
isinstance(session.address, tuple) and session.address[0] or session.address)
|
||||
else:
|
||||
# unprivileged
|
||||
table = evtable.EvTable("|wPlayer name", "|wOn for", "|wIdle")
|
||||
table = evtable.EvTable("|wAccount name", "|wOn for", "|wIdle")
|
||||
for session in session_list:
|
||||
if not session.logged_in:
|
||||
continue
|
||||
delta_cmd = time.time() - session.cmd_last_visible
|
||||
delta_conn = time.time() - session.conn_time
|
||||
player = session.get_player()
|
||||
table.add_row(utils.crop(player.key, width=25),
|
||||
account = session.get_account()
|
||||
table.add_row(utils.crop(account.key, width=25),
|
||||
utils.time_format(delta_conn, 0),
|
||||
utils.time_format(delta_cmd, 1))
|
||||
is_one = nplayers == 1
|
||||
self.msg("|wPlayers:|n\n%s\n%s unique account%s logged in."
|
||||
% (table, "One" if is_one else nplayers, "" if is_one else "s"))
|
||||
is_one = naccounts == 1
|
||||
self.msg("|wAccounts:|n\n%s\n%s unique account%s logged in."
|
||||
% (table, "One" if is_one else naccounts, "" if is_one else "s"))
|
||||
|
||||
|
||||
class CmdOption(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -470,7 +470,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
|
|||
locks = "cmd:all()"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
|
|
@ -585,15 +585,15 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
|
|||
# a valid setting
|
||||
if "save" in self.switches:
|
||||
# save this option only
|
||||
saved_options = self.player.attributes.get("_saved_protocol_flags", default={})
|
||||
saved_options = self.account.attributes.get("_saved_protocol_flags", default={})
|
||||
saved_options.update(optiondict)
|
||||
self.player.attributes.add("_saved_protocol_flags", saved_options)
|
||||
self.account.attributes.add("_saved_protocol_flags", saved_options)
|
||||
for key in optiondict:
|
||||
self.msg("|gSaved option %s.|n" % key)
|
||||
if "clear" in self.switches:
|
||||
# clear this save
|
||||
for key in optiondict:
|
||||
self.player.attributes.get("_saved_protocol_flags", {}).pop(key, None)
|
||||
self.account.attributes.get("_saved_protocol_flags", {}).pop(key, None)
|
||||
self.msg("|gCleared saved %s." % key)
|
||||
self.session.update_flags(**optiondict)
|
||||
|
||||
|
|
@ -608,27 +608,27 @@ class CmdPassword(COMMAND_DEFAULT_CLASS):
|
|||
Changes your password. Make sure to pick a safe one.
|
||||
"""
|
||||
key = "@password"
|
||||
locks = "cmd:pperm(Players)"
|
||||
locks = "cmd:pperm(Account)"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""hook function."""
|
||||
|
||||
player = self.player
|
||||
account = self.account
|
||||
if not self.rhs:
|
||||
self.msg("Usage: @password <oldpass> = <newpass>")
|
||||
return
|
||||
oldpass = self.lhslist[0] # Both of these are
|
||||
newpass = self.rhslist[0] # already stripped by parse()
|
||||
if not player.check_password(oldpass):
|
||||
if not account.check_password(oldpass):
|
||||
self.msg("The specified old password isn't correct.")
|
||||
elif len(newpass) < 3:
|
||||
self.msg("Passwords must be at least three characters long.")
|
||||
else:
|
||||
player.set_password(newpass)
|
||||
player.save()
|
||||
account.set_password(newpass)
|
||||
account.save()
|
||||
self.msg("Password changed.")
|
||||
|
||||
|
||||
|
|
@ -646,30 +646,29 @@ class CmdQuit(COMMAND_DEFAULT_CLASS):
|
|||
game. Use the /all switch to disconnect from all sessions.
|
||||
"""
|
||||
key = "@quit"
|
||||
aliases = "quit"
|
||||
locks = "cmd:all()"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""hook function"""
|
||||
player = self.player
|
||||
account = self.account
|
||||
|
||||
if 'all' in self.switches:
|
||||
player.msg("|RQuitting|n all sessions. Hope to see you soon again.", session=self.session)
|
||||
for session in player.sessions.all():
|
||||
player.disconnect_session_from_player(session)
|
||||
account.msg("|RQuitting|n all sessions. Hope to see you soon again.", session=self.session)
|
||||
for session in account.sessions.all():
|
||||
account.disconnect_session_from_account(session)
|
||||
else:
|
||||
nsess = len(player.sessions.all())
|
||||
nsess = len(account.sessions.all())
|
||||
if nsess == 2:
|
||||
player.msg("|RQuitting|n. One session is still connected.", session=self.session)
|
||||
account.msg("|RQuitting|n. One session is still connected.", session=self.session)
|
||||
elif nsess > 2:
|
||||
player.msg("|RQuitting|n. %i sessions are still connected." % (nsess-1), session=self.session)
|
||||
account.msg("|RQuitting|n. %i sessions are still connected." % (nsess-1), session=self.session)
|
||||
else:
|
||||
# we are quitting the last available session
|
||||
player.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session)
|
||||
player.disconnect_session_from_player(self.session)
|
||||
account.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session)
|
||||
account.disconnect_session_from_account(self.session)
|
||||
|
||||
|
||||
class CmdColorTest(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -686,12 +685,19 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
|
|||
color - if not you will see rubbish appear.
|
||||
"""
|
||||
key = "@color"
|
||||
aliases = "color"
|
||||
locks = "cmd:all()"
|
||||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
# the slices of the ANSI_PARSER lists to use for retrieving the
|
||||
# relevant color tags to display. Replace if using another schema.
|
||||
# This command can only show one set of markup.
|
||||
slice_bright_fg = slice(7, 15) # from ANSI_PARSER.ansi_map
|
||||
slice_dark_fg = slice(15, 23) # from ANSI_PARSER.ansi_map
|
||||
slice_dark_bg = slice(-8, None) # from ANSI_PARSER.ansi_map
|
||||
slice_bright_bg = slice(None, None) # from ANSI_PARSER.ansi_xterm256_bright_bg_map
|
||||
|
||||
def table_format(self, table):
|
||||
"""
|
||||
|
|
@ -718,14 +724,16 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
|
|||
ap = ansi.ANSI_PARSER
|
||||
# ansi colors
|
||||
# show all ansi color-related codes
|
||||
col1 = ["%s%s|n" % (code, code.replace("|", "||")) for code, _ in ap.ext_ansi_map[48:56]]
|
||||
col2 = ["%s%s|n" % (code, code.replace("|", "||")) for code, _ in ap.ext_ansi_map[56:64]]
|
||||
col3 = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
|
||||
for code, _ in ap.ext_ansi_map[-8:]]
|
||||
col4 = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
|
||||
for code, _ in ap.ansi_bright_bgs[-8:]]
|
||||
col2.extend(["" for _ in range(len(col1)-len(col2))])
|
||||
table = utils.format_table([col1, col2, col4, col3])
|
||||
bright_fg = ["%s%s|n" % (code, code.replace("|", "||"))
|
||||
for code, _ in ap.ansi_map[self.slice_bright_fg]]
|
||||
dark_fg = ["%s%s|n" % (code, code.replace("|", "||"))
|
||||
for code, _ in ap.ansi_map[self.slice_dark_fg]]
|
||||
dark_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
|
||||
for code, _ in ap.ansi_map[self.slice_dark_bg]]
|
||||
bright_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
|
||||
for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg]]
|
||||
dark_fg.extend(["" for _ in range(len(bright_fg)-len(dark_fg))])
|
||||
table = utils.format_table([bright_fg, dark_fg, bright_bg, dark_bg])
|
||||
string = "ANSI colors:"
|
||||
for row in table:
|
||||
string += "\n " + " ".join(row)
|
||||
|
|
@ -776,30 +784,30 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
class CmdQuell(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
use character's permissions instead of player's
|
||||
use character's permissions instead of account's
|
||||
|
||||
Usage:
|
||||
quell
|
||||
unquell
|
||||
|
||||
Normally the permission level of the Player is used when puppeting a
|
||||
Normally the permission level of the Account is used when puppeting a
|
||||
Character/Object to determine access. This command will switch the lock
|
||||
system to make use of the puppeted Object's permissions instead. This is
|
||||
useful mainly for testing.
|
||||
Hierarchical permission quelling only work downwards, thus a Player cannot
|
||||
Hierarchical permission quelling only work downwards, thus an Account cannot
|
||||
use a higher-permission Character to escalate their permission level.
|
||||
Use the unquell command to revert back to normal operation.
|
||||
"""
|
||||
|
||||
key = "@quell"
|
||||
aliases = ["@unquell"]
|
||||
locks = "cmd:pperm(Players)"
|
||||
locks = "cmd:pperm(Account)"
|
||||
help_category = "General"
|
||||
|
||||
# this is used by the parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def _recache_locks(self, player):
|
||||
def _recache_locks(self, account):
|
||||
"""Helper method to reset the lockhandler on an already puppeted object"""
|
||||
if self.session:
|
||||
char = self.session.puppet
|
||||
|
|
@ -808,31 +816,31 @@ class CmdQuell(COMMAND_DEFAULT_CLASS):
|
|||
# the lock caches (otherwise the superuser status change
|
||||
# won't be visible until repuppet)
|
||||
char.locks.reset()
|
||||
player.locks.reset()
|
||||
account.locks.reset()
|
||||
|
||||
def func(self):
|
||||
"""Perform the command"""
|
||||
player = self.player
|
||||
permstr = player.is_superuser and " (superuser)" or "(%s)" % (", ".join(player.permissions.all()))
|
||||
account = self.account
|
||||
permstr = account.is_superuser and " (superuser)" or "(%s)" % (", ".join(account.permissions.all()))
|
||||
if self.cmdstring == '@unquell':
|
||||
if not player.attributes.get('_quell'):
|
||||
self.msg("Already using normal Player permissions %s." % permstr)
|
||||
if not account.attributes.get('_quell'):
|
||||
self.msg("Already using normal Account permissions %s." % permstr)
|
||||
else:
|
||||
player.attributes.remove('_quell')
|
||||
self.msg("Player permissions %s restored." % permstr)
|
||||
account.attributes.remove('_quell')
|
||||
self.msg("Account permissions %s restored." % permstr)
|
||||
else:
|
||||
if player.attributes.get('_quell'):
|
||||
self.msg("Already quelling Player %s permissions." % permstr)
|
||||
if account.attributes.get('_quell'):
|
||||
self.msg("Already quelling Account %s permissions." % permstr)
|
||||
return
|
||||
player.attributes.add('_quell', True)
|
||||
account.attributes.add('_quell', True)
|
||||
puppet = self.session.puppet
|
||||
if puppet:
|
||||
cpermstr = "(%s)" % ", ".join(puppet.permissions.all())
|
||||
cpermstr = "Quelling to current puppet's permissions %s." % cpermstr
|
||||
cpermstr += "\n(Note: If this is higher than Player permissions %s," \
|
||||
cpermstr += "\n(Note: If this is higher than Account permissions %s," \
|
||||
" the lowest of the two will be used.)" % permstr
|
||||
cpermstr += "\nUse @unquell to return to normal permission usage."
|
||||
self.msg(cpermstr)
|
||||
else:
|
||||
self.msg("Quelling Player permissions%s. Use @unquell to get them back." % permstr)
|
||||
self._recache_locks(player)
|
||||
self.msg("Quelling Account permissions%s. Use @unquell to get them back." % permstr)
|
||||
self._recache_locks(account)
|
||||
|
|
@ -16,27 +16,27 @@ COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
|||
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
|
||||
|
||||
# limit members for API inclusion
|
||||
__all__ = ("CmdBoot", "CmdBan", "CmdUnban", "CmdDelPlayer",
|
||||
__all__ = ("CmdBoot", "CmdBan", "CmdUnban", "CmdDelAccount",
|
||||
"CmdEmit", "CmdNewPassword", "CmdPerm", "CmdWall")
|
||||
|
||||
|
||||
class CmdBoot(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
kick a player from the server.
|
||||
kick an account from the server.
|
||||
|
||||
Usage
|
||||
@boot[/switches] <player obj> [: reason]
|
||||
@boot[/switches] <account obj> [: reason]
|
||||
|
||||
Switches:
|
||||
quiet - Silently boot without informing player
|
||||
quiet - Silently boot without informing account
|
||||
sid - boot by session id instead of name or dbref
|
||||
|
||||
Boot a player object from the server. If a reason is
|
||||
Boot an account object from the server. If a reason is
|
||||
supplied it will be echoed to the user unless /quiet is set.
|
||||
"""
|
||||
|
||||
key = "@boot"
|
||||
locks = "cmd:perm(boot) or perm(Wizards)"
|
||||
locks = "cmd:perm(boot) or perm(Admin)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -45,7 +45,7 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
|
|||
args = self.args
|
||||
|
||||
if not args:
|
||||
caller.msg("Usage: @boot[/switches] <player> [:reason]")
|
||||
caller.msg("Usage: @boot[/switches] <account> [:reason]")
|
||||
return
|
||||
|
||||
if ':' in args:
|
||||
|
|
@ -64,10 +64,10 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
|
|||
boot_list.append(sess)
|
||||
break
|
||||
else:
|
||||
# Boot by player object
|
||||
pobj = search.player_search(args)
|
||||
# Boot by account object
|
||||
pobj = search.account_search(args)
|
||||
if not pobj:
|
||||
caller.msg("Player %s was not found." % args)
|
||||
caller.msg("Account %s was not found." % args)
|
||||
return
|
||||
pobj = pobj[0]
|
||||
if not pobj.access(caller, 'boot'):
|
||||
|
|
@ -75,12 +75,12 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
|
|||
caller.msg(string)
|
||||
return
|
||||
# we have a bootable object with a connected user
|
||||
matches = SESSIONS.sessions_from_player(pobj)
|
||||
matches = SESSIONS.sessions_from_account(pobj)
|
||||
for match in matches:
|
||||
boot_list.append(match)
|
||||
|
||||
if not boot_list:
|
||||
caller.msg("No matching sessions found. The Player does not seem to be online.")
|
||||
caller.msg("No matching sessions found. The Account does not seem to be online.")
|
||||
return
|
||||
|
||||
# Carry out the booting of the sessions in the boot list.
|
||||
|
|
@ -93,7 +93,7 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
for session in boot_list:
|
||||
session.msg(feedback)
|
||||
session.player.disconnect_session_from_player(session)
|
||||
session.account.disconnect_session_from_account(session)
|
||||
|
||||
|
||||
# regex matching IP addresses with wildcards, eg. 233.122.4.*
|
||||
|
|
@ -118,7 +118,7 @@ def list_bans(banlist):
|
|||
|
||||
class CmdBan(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
ban a player from the server
|
||||
ban an account from the server
|
||||
|
||||
Usage:
|
||||
@ban [<name or ip> [: reason]]
|
||||
|
|
@ -128,8 +128,8 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
|
|||
This command bans a user from accessing the game. Supply an optional
|
||||
reason to be able to later remember why the ban was put in place.
|
||||
|
||||
It is often preferable to ban a player from the server than to
|
||||
delete a player with @delplayer. If banned by name, that player
|
||||
It is often preferable to ban an account from the server than to
|
||||
delete an account with @delaccount. If banned by name, that account
|
||||
account can no longer be logged into.
|
||||
|
||||
IP (Internet Protocol) address banning allows blocking all access
|
||||
|
|
@ -151,7 +151,7 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@ban"
|
||||
aliases = ["@bans"]
|
||||
locks = "cmd:perm(ban) or perm(Immortals)"
|
||||
locks = "cmd:perm(ban) or perm(Developer)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -206,19 +206,19 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
class CmdUnban(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
remove a ban from a player
|
||||
remove a ban from an account
|
||||
|
||||
Usage:
|
||||
@unban <banid>
|
||||
|
||||
This will clear a player name/ip ban previously set with the @ban
|
||||
This will clear an account name/ip ban previously set with the @ban
|
||||
command. Use this command without an argument to view a numbered
|
||||
list of bans. Use the numbers in this list to select which one to
|
||||
unban.
|
||||
|
||||
"""
|
||||
key = "@unban"
|
||||
locks = "cmd:perm(unban) or perm(Immortals)"
|
||||
locks = "cmd:perm(unban) or perm(Developer)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -249,23 +249,23 @@ class CmdUnban(COMMAND_DEFAULT_CLASS):
|
|||
(num, " ".join([s for s in ban[:2]])))
|
||||
|
||||
|
||||
class CmdDelPlayer(COMMAND_DEFAULT_CLASS):
|
||||
class CmdDelAccount(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
delete a player from the server
|
||||
delete an account from the server
|
||||
|
||||
Usage:
|
||||
@delplayer[/switch] <name> [: reason]
|
||||
@delaccount[/switch] <name> [: reason]
|
||||
|
||||
Switch:
|
||||
delobj - also delete the player's currently
|
||||
delobj - also delete the account's currently
|
||||
assigned in-game object.
|
||||
|
||||
Completely deletes a user from the server database,
|
||||
making their nick and e-mail again available.
|
||||
"""
|
||||
|
||||
key = "@delplayer"
|
||||
locks = "cmd:perm(delplayer) or perm(Immortals)"
|
||||
key = "@delaccount"
|
||||
locks = "cmd:perm(delaccount) or perm(Developer)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -274,49 +274,49 @@ class CmdDelPlayer(COMMAND_DEFAULT_CLASS):
|
|||
caller = self.caller
|
||||
args = self.args
|
||||
|
||||
if hasattr(caller, 'player'):
|
||||
caller = caller.player
|
||||
if hasattr(caller, 'account'):
|
||||
caller = caller.account
|
||||
|
||||
if not args:
|
||||
self.msg("Usage: @delplayer <player/user name or #id> [: reason]")
|
||||
self.msg("Usage: @delaccount <account/user name or #id> [: reason]")
|
||||
return
|
||||
|
||||
reason = ""
|
||||
if ':' in args:
|
||||
args, reason = [arg.strip() for arg in args.split(':', 1)]
|
||||
|
||||
# We use player_search since we want to be sure to find also players
|
||||
# We use account_search since we want to be sure to find also accounts
|
||||
# that lack characters.
|
||||
players = search.player_search(args)
|
||||
accounts = search.account_search(args)
|
||||
|
||||
if not players:
|
||||
self.msg('Could not find a player by that name.')
|
||||
if not accounts:
|
||||
self.msg('Could not find an account by that name.')
|
||||
return
|
||||
|
||||
if len(players) > 1:
|
||||
if len(accounts) > 1:
|
||||
string = "There were multiple matches:\n"
|
||||
string += "\n".join(" %s %s" % (player.id, player.key) for player in players)
|
||||
string += "\n".join(" %s %s" % (account.id, account.key) for account in accounts)
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
# one single match
|
||||
|
||||
player = players.pop()
|
||||
account = accounts.pop()
|
||||
|
||||
if not player.access(caller, 'delete'):
|
||||
string = "You don't have the permissions to delete that player."
|
||||
if not account.access(caller, 'delete'):
|
||||
string = "You don't have the permissions to delete that account."
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
uname = player.username
|
||||
# boot the player then delete
|
||||
self.msg("Informing and disconnecting player ...")
|
||||
uname = account.username
|
||||
# boot the account then delete
|
||||
self.msg("Informing and disconnecting account ...")
|
||||
string = "\nYour account '%s' is being *permanently* deleted.\n" % uname
|
||||
if reason:
|
||||
string += " Reason given:\n '%s'" % reason
|
||||
player.msg(string)
|
||||
player.delete()
|
||||
self.msg("Player %s was successfully deleted." % uname)
|
||||
account.msg(string)
|
||||
account.delete()
|
||||
self.msg("Account %s was successfully deleted." % uname)
|
||||
|
||||
|
||||
class CmdEmit(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -330,18 +330,18 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
Switches:
|
||||
room : limit emits to rooms only (default)
|
||||
players : limit emits to players only
|
||||
accounts : limit emits to accounts only
|
||||
contents : send to the contents of matched objects too
|
||||
|
||||
Emits a message to the selected objects or to
|
||||
your immediate surroundings. If the object is a room,
|
||||
send to its contents. @remit and @pemit are just
|
||||
limited forms of @emit, for sending to rooms and
|
||||
to players respectively.
|
||||
to accounts respectively.
|
||||
"""
|
||||
key = "@emit"
|
||||
aliases = ["@pemit", "@remit"]
|
||||
locks = "cmd:perm(emit) or perm(Builders)"
|
||||
locks = "cmd:perm(emit) or perm(Builder)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -359,7 +359,7 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
rooms_only = 'rooms' in self.switches
|
||||
players_only = 'players' in self.switches
|
||||
accounts_only = 'accounts' in self.switches
|
||||
send_to_contents = 'contents' in self.switches
|
||||
|
||||
# we check which command was used to force the switches
|
||||
|
|
@ -367,7 +367,7 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
|
|||
rooms_only = True
|
||||
send_to_contents = True
|
||||
elif self.cmdstring == '@pemit':
|
||||
players_only = True
|
||||
accounts_only = True
|
||||
|
||||
if not self.rhs:
|
||||
message = self.args
|
||||
|
|
@ -384,8 +384,8 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
|
|||
if rooms_only and obj.location is not None:
|
||||
caller.msg("%s is not a room. Ignored." % objname)
|
||||
continue
|
||||
if players_only and not obj.has_player:
|
||||
caller.msg("%s has no active player. Ignored." % objname)
|
||||
if accounts_only and not obj.has_account:
|
||||
caller.msg("%s has no active account. Ignored." % objname)
|
||||
continue
|
||||
if obj.access(caller, 'tell'):
|
||||
obj.msg(message)
|
||||
|
|
@ -400,16 +400,16 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
class CmdNewPassword(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
change the password of a player
|
||||
change the password of an account
|
||||
|
||||
Usage:
|
||||
@userpassword <user obj> = <new password>
|
||||
|
||||
Set a player's password.
|
||||
Set an account's password.
|
||||
"""
|
||||
|
||||
key = "@userpassword"
|
||||
locks = "cmd:perm(newpassword) or perm(Wizards)"
|
||||
locks = "cmd:perm(newpassword) or perm(Admin)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -421,36 +421,36 @@ class CmdNewPassword(COMMAND_DEFAULT_CLASS):
|
|||
self.msg("Usage: @userpassword <user obj> = <new password>")
|
||||
return
|
||||
|
||||
# the player search also matches 'me' etc.
|
||||
player = caller.search_player(self.lhs)
|
||||
if not player:
|
||||
# the account search also matches 'me' etc.
|
||||
account = caller.search_account(self.lhs)
|
||||
if not account:
|
||||
return
|
||||
player.set_password(self.rhs)
|
||||
player.save()
|
||||
self.msg("%s - new password set to '%s'." % (player.name, self.rhs))
|
||||
if player.character != caller:
|
||||
player.msg("%s has changed your password to '%s'." % (caller.name,
|
||||
account.set_password(self.rhs)
|
||||
account.save()
|
||||
self.msg("%s - new password set to '%s'." % (account.name, self.rhs))
|
||||
if account.character != caller:
|
||||
account.msg("%s has changed your password to '%s'." % (caller.name,
|
||||
self.rhs))
|
||||
|
||||
|
||||
class CmdPerm(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
set the permissions of a player/object
|
||||
set the permissions of an account/object
|
||||
|
||||
Usage:
|
||||
@perm[/switch] <object> [= <permission>[,<permission>,...]]
|
||||
@perm[/switch] *<player> [= <permission>[,<permission>,...]]
|
||||
@perm[/switch] *<account> [= <permission>[,<permission>,...]]
|
||||
|
||||
Switches:
|
||||
del : delete the given permission from <object> or <player>.
|
||||
player : set permission on a player (same as adding * to name)
|
||||
del : delete the given permission from <object> or <account>.
|
||||
account : set permission on an account (same as adding * to name)
|
||||
|
||||
This command sets/clears individual permission strings on an object
|
||||
or player. If no permission is given, list all permissions on <object>.
|
||||
or account. If no permission is given, list all permissions on <object>.
|
||||
"""
|
||||
key = "@perm"
|
||||
aliases = "@setperm"
|
||||
locks = "cmd:perm(perm) or perm(Immortals)"
|
||||
locks = "cmd:perm(perm) or perm(Developer)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -465,11 +465,11 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
|
|||
caller.msg(string)
|
||||
return
|
||||
|
||||
playermode = 'player' in self.switches or lhs.startswith('*')
|
||||
accountmode = 'account' in self.switches or lhs.startswith('*')
|
||||
lhs = lhs.lstrip("*")
|
||||
|
||||
if playermode:
|
||||
obj = caller.search_player(lhs)
|
||||
if accountmode:
|
||||
obj = caller.search_account(lhs)
|
||||
else:
|
||||
obj = caller.search(lhs, global_search=True)
|
||||
if not obj:
|
||||
|
|
@ -485,19 +485,19 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
|
|||
string += "<None>"
|
||||
else:
|
||||
string += ", ".join(obj.permissions.all())
|
||||
if (hasattr(obj, 'player') and
|
||||
hasattr(obj.player, 'is_superuser') and
|
||||
obj.player.is_superuser):
|
||||
if (hasattr(obj, 'account') and
|
||||
hasattr(obj.account, 'is_superuser') and
|
||||
obj.account.is_superuser):
|
||||
string += "\n(... but this object is currently controlled by a SUPERUSER! "
|
||||
string += "All access checks are passed automatically.)"
|
||||
caller.msg(string)
|
||||
return
|
||||
|
||||
# we supplied an argument on the form obj = perm
|
||||
locktype = "edit" if playermode else "control"
|
||||
locktype = "edit" if accountmode else "control"
|
||||
if not obj.access(caller, locktype):
|
||||
caller.msg("You are not allowed to edit this %s's permissions."
|
||||
% ("player" if playermode else "object"))
|
||||
% ("account" if accountmode else "object"))
|
||||
return
|
||||
|
||||
caller_result = []
|
||||
|
|
@ -528,7 +528,7 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
|
|||
caller_result.append("\nPermission '%s' is already defined on %s." % (rhs, obj.name))
|
||||
else:
|
||||
obj.permissions.add(perm)
|
||||
plystring = "the Player" if playermode else "the Object/Character"
|
||||
plystring = "the Account" if accountmode else "the Object/Character"
|
||||
caller_result.append("\nPermission '%s' given to %s (%s)." % (rhs, obj.name, plystring))
|
||||
target_result.append("\n%s gives you (%s, %s) the permission '%s'."
|
||||
% (caller.name, obj.name, plystring, rhs))
|
||||
|
|
@ -544,10 +544,10 @@ class CmdWall(COMMAND_DEFAULT_CLASS):
|
|||
Usage:
|
||||
@wall <message>
|
||||
|
||||
Announces a message to all connected players.
|
||||
Announces a message to all connected accounts.
|
||||
"""
|
||||
key = "@wall"
|
||||
locks = "cmd:perm(wall) or perm(Wizards)"
|
||||
locks = "cmd:perm(wall) or perm(Admin)"
|
||||
help_category = "Admin"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -556,5 +556,5 @@ class CmdWall(COMMAND_DEFAULT_CLASS):
|
|||
self.caller.msg("Usage: @wall <message>")
|
||||
return
|
||||
message = "%s shouts \"%s\"" % (self.caller.name, self.args)
|
||||
self.msg("Announcing to all connected players ...")
|
||||
self.msg("Announcing to all connected accounts ...")
|
||||
SESSIONS.announce_all(message)
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@batchcommands"
|
||||
aliases = ["@batchcommand", "@batchcmd"]
|
||||
locks = "cmd:perm(batchcommands) or superuser()"
|
||||
locks = "cmd:perm(batchcommands) or perm(Developer)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@alias"
|
||||
aliases = "@setobjalias"
|
||||
locks = "cmd:perm(setobjalias) or perm(Builders)"
|
||||
locks = "cmd:perm(setobjalias) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -196,7 +196,7 @@ class CmdCopy(ObjManipCommand):
|
|||
"""
|
||||
|
||||
key = "@copy"
|
||||
locks = "cmd:perm(copy) or perm(Builders)"
|
||||
locks = "cmd:perm(copy) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -276,7 +276,7 @@ class CmdCpAttr(ObjManipCommand):
|
|||
If you don't supply a source object, yourself is used.
|
||||
"""
|
||||
key = "@cpattr"
|
||||
locks = "cmd:perm(cpattr) or perm(Builders)"
|
||||
locks = "cmd:perm(cpattr) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def check_from_attr(self, obj, attr, clear=False):
|
||||
|
|
@ -418,7 +418,7 @@ class CmdMvAttr(ObjManipCommand):
|
|||
object. If you don't supply a source object, yourself is used.
|
||||
"""
|
||||
key = "@mvattr"
|
||||
locks = "cmd:perm(mvattr) or perm(Builders)"
|
||||
locks = "cmd:perm(mvattr) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -466,12 +466,12 @@ class CmdCreate(ObjManipCommand):
|
|||
"""
|
||||
|
||||
key = "@create"
|
||||
locks = "cmd:perm(create) or perm(Builders)"
|
||||
locks = "cmd:perm(create) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
# lockstring of newly created objects, for easy overloading.
|
||||
# Will be formatted with the {id} of the creating object.
|
||||
new_obj_lockstring = "control:id({id}) or perm(Wizards);delete:id({id}) or perm(Wizards)"
|
||||
new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)"
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
|
|
@ -535,10 +535,10 @@ def _desc_quit(caller):
|
|||
|
||||
class CmdDesc(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
describe an object
|
||||
describe an object or the current room.
|
||||
|
||||
Usage:
|
||||
@desc [<obj> =] <description>
|
||||
@setdesc [<obj> =] <description>
|
||||
|
||||
Switches:
|
||||
edit - Open up a line editor for more advanced editing.
|
||||
|
|
@ -546,9 +546,9 @@ class CmdDesc(COMMAND_DEFAULT_CLASS):
|
|||
Sets the "desc" attribute on an object. If an object is not given,
|
||||
describe the current room.
|
||||
"""
|
||||
key = "@desc"
|
||||
key = "@setdesc"
|
||||
aliases = "@describe"
|
||||
locks = "cmd:perm(desc) or perm(Builders)"
|
||||
locks = "cmd:perm(desc) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def edit_handler(self):
|
||||
|
|
@ -607,7 +607,7 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
switches:
|
||||
override - The @destroy command will usually avoid accidentally
|
||||
destroying player objects. This switch overrides this safety.
|
||||
destroying account objects. This switch overrides this safety.
|
||||
examples:
|
||||
@destroy house, roof, door, 44-78
|
||||
@destroy 5-10, flower, 45
|
||||
|
|
@ -618,7 +618,7 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@destroy"
|
||||
aliases = ["@delete", "@del"]
|
||||
locks = "cmd:perm(destroy) or perm(Builders)"
|
||||
locks = "cmd:perm(destroy) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -640,8 +640,8 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
|
|||
objname = obj.name
|
||||
if not (obj.access(caller, "control") or obj.access(caller, 'delete')):
|
||||
return "\nYou don't have permission to delete %s." % objname
|
||||
if obj.player and not 'override' in self.switches:
|
||||
return "\nObject %s is controlled by an active player. Use /override to delete anyway." % objname
|
||||
if obj.account and not 'override' in self.switches:
|
||||
return "\nObject %s is controlled by an active account. Use /override to delete anyway." % objname
|
||||
if obj.dbid == int(settings.DEFAULT_HOME.lstrip("#")):
|
||||
return "\nYou are trying to delete |c%s|n, which is set as DEFAULT_HOME. " \
|
||||
"Re-point settings.DEFAULT_HOME to another " \
|
||||
|
|
@ -703,14 +703,14 @@ class CmdDig(ObjManipCommand):
|
|||
would be 'north;no;n'.
|
||||
"""
|
||||
key = "@dig"
|
||||
locks = "cmd:perm(dig) or perm(Builders)"
|
||||
locks = "cmd:perm(dig) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
# lockstring of newly created rooms, for easy overloading.
|
||||
# Will be formatted with the {id} of the creating object.
|
||||
new_room_lockstring = "control:id({id}) or perm(Wizards); " \
|
||||
"delete:id({id}) or perm(Wizards); " \
|
||||
"edit:id({id}) or perm(Wizards)"
|
||||
new_room_lockstring = "control:id({id}) or perm(Admin); " \
|
||||
"delete:id({id}) or perm(Admin); " \
|
||||
"edit:id({id}) or perm(Admin)"
|
||||
|
||||
def func(self):
|
||||
"Do the digging. Inherits variables from ObjManipCommand.parse()"
|
||||
|
|
@ -847,7 +847,7 @@ class CmdTunnel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@tunnel"
|
||||
aliases = ["@tun"]
|
||||
locks = "cmd: perm(tunnel) or perm(Builders)"
|
||||
locks = "cmd: perm(tunnel) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
# store the direction, full name and its opposite
|
||||
|
|
@ -920,7 +920,7 @@ class CmdLink(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
|
||||
key = "@link"
|
||||
locks = "cmd:perm(link) or perm(Builders)"
|
||||
locks = "cmd:perm(link) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -998,7 +998,7 @@ class CmdUnLink(CmdLink):
|
|||
# this is just a child of CmdLink
|
||||
|
||||
key = "@unlink"
|
||||
locks = "cmd:perm(unlink) or perm(Builders)"
|
||||
locks = "cmd:perm(unlink) or perm(Builder)"
|
||||
help_key = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1035,9 +1035,8 @@ class CmdSetHome(CmdLink):
|
|||
If no location is given, just view the object's home location.
|
||||
"""
|
||||
|
||||
key = "@home"
|
||||
aliases = "@sethome"
|
||||
locks = "cmd:perm(@home) or perm(Builders)"
|
||||
key = "@sethome"
|
||||
locks = "cmd:perm(@home) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1084,7 +1083,7 @@ class CmdListCmdSets(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@cmdsets"
|
||||
aliases = "@listcmsets"
|
||||
locks = "cmd:perm(listcmdsets) or perm(Builders)"
|
||||
locks = "cmd:perm(listcmdsets) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1109,13 +1108,13 @@ class CmdName(ObjManipCommand):
|
|||
@name obj = name;alias1;alias2
|
||||
|
||||
Rename an object to something new. Use *obj to
|
||||
rename a player.
|
||||
rename an account.
|
||||
|
||||
"""
|
||||
|
||||
key = "@name"
|
||||
aliases = ["@rename"]
|
||||
locks = "cmd:perm(rename) or perm(Builders)"
|
||||
locks = "cmd:perm(rename) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1130,22 +1129,22 @@ class CmdName(ObjManipCommand):
|
|||
if self.lhs_objs:
|
||||
objname = self.lhs_objs[0]['name']
|
||||
if objname.startswith("*"):
|
||||
# player mode
|
||||
obj = caller.player.search(objname.lstrip("*"))
|
||||
# account mode
|
||||
obj = caller.account.search(objname.lstrip("*"))
|
||||
if obj:
|
||||
if self.rhs_objs[0]['aliases']:
|
||||
caller.msg("Players can't have aliases.")
|
||||
caller.msg("Accounts can't have aliases.")
|
||||
return
|
||||
newname = self.rhs
|
||||
if not newname:
|
||||
caller.msg("No name defined!")
|
||||
return
|
||||
if not (obj.access(caller, "control") or obj.access(caller, "edit")):
|
||||
caller.msg("You don't have right to edit this player %s." % obj)
|
||||
caller.msg("You don't have right to edit this account %s." % obj)
|
||||
return
|
||||
obj.username = newname
|
||||
obj.save()
|
||||
caller.msg("Player's name changed to '%s'." % newname)
|
||||
caller.msg("Account's name changed to '%s'." % newname)
|
||||
return
|
||||
# object search, also with *
|
||||
obj = caller.search(objname)
|
||||
|
|
@ -1191,7 +1190,7 @@ class CmdOpen(ObjManipCommand):
|
|||
|
||||
"""
|
||||
key = "@open"
|
||||
locks = "cmd:perm(open) or perm(Builders)"
|
||||
locks = "cmd:perm(open) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
# a custom member method to chug out exits and do checks
|
||||
|
|
@ -1327,7 +1326,7 @@ def _convert_from_string(cmd, strobj):
|
|||
be converted to a string and a warning will be given.
|
||||
|
||||
We need to convert like this since all data being sent over the
|
||||
telnet connection by the Player is text - but we will want to
|
||||
telnet connection by the Account is text - but we will want to
|
||||
store it as the "real" python type so we can do convenient
|
||||
comparisons later (e.g. obj.db.value = 2, if value is stored as a
|
||||
string this will always fail).
|
||||
|
|
@ -1382,13 +1381,13 @@ def _convert_from_string(cmd, strobj):
|
|||
|
||||
class CmdSetAttribute(ObjManipCommand):
|
||||
"""
|
||||
set attribute on an object or player
|
||||
set attribute on an object or account
|
||||
|
||||
Usage:
|
||||
@set <obj>/<attr> = <value>
|
||||
@set <obj>/<attr> =
|
||||
@set <obj>/<attr>
|
||||
@set *<player>/attr = <value>
|
||||
@set *<account>/attr = <value>
|
||||
|
||||
Switch:
|
||||
edit: Open the line editor (string values only)
|
||||
|
|
@ -1413,14 +1412,14 @@ class CmdSetAttribute(ObjManipCommand):
|
|||
"""
|
||||
|
||||
key = "@set"
|
||||
locks = "cmd:perm(set) or perm(Builders)"
|
||||
locks = "cmd:perm(set) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def check_obj(self, obj):
|
||||
"""
|
||||
This may be overridden by subclasses in case restrictions need to be
|
||||
placed on whether certain objects can have attributes set by certain
|
||||
players.
|
||||
accounts.
|
||||
|
||||
This function is expected to display its own error message.
|
||||
|
||||
|
|
@ -1506,7 +1505,7 @@ class CmdSetAttribute(ObjManipCommand):
|
|||
attrs = self.lhs_objattr[0]['attrs']
|
||||
|
||||
if objname.startswith('*'):
|
||||
obj = caller.search_player(objname.lstrip('*'))
|
||||
obj = caller.search_account(objname.lstrip('*'))
|
||||
else:
|
||||
obj = caller.search(objname)
|
||||
if not obj:
|
||||
|
|
@ -1595,7 +1594,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@typeclass"
|
||||
aliases = ["@type", "@parent", "@swap", "@update"]
|
||||
locks = "cmd:perm(typeclass) or perm(Builders)"
|
||||
locks = "cmd:perm(typeclass) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1685,7 +1684,7 @@ class CmdWipe(ObjManipCommand):
|
|||
matching the given attribute-wildcard search string.
|
||||
"""
|
||||
key = "@wipe"
|
||||
locks = "cmd:perm(wipe) or perm(Builders)"
|
||||
locks = "cmd:perm(wipe) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1743,18 +1742,18 @@ class CmdLock(ObjManipCommand):
|
|||
Separator expressions need not be capitalized.
|
||||
|
||||
For example:
|
||||
'get: id(25) or perm(Wizards)'
|
||||
'get: id(25) or perm(Admin)'
|
||||
The 'get' access_type is checked by the get command and will
|
||||
an object locked with this string will only be possible to
|
||||
pick up by Wizards or by object with id 25.
|
||||
pick up by Admins or by object with id=25.
|
||||
|
||||
You can add several access_types after oneanother by separating
|
||||
them by ';', i.e:
|
||||
'get:id(25);delete:perm(Builders)'
|
||||
'get:id(25);delete:perm(Builder)'
|
||||
"""
|
||||
key = "@lock"
|
||||
aliases = ["@locks", "lock", "locks"]
|
||||
locks = "cmd: perm(locks) or perm(Builders)"
|
||||
aliases = ["@locks"]
|
||||
locks = "cmd: perm(locks) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1832,26 +1831,26 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
Usage:
|
||||
examine [<object>[/attrname]]
|
||||
examine [*<player>[/attrname]]
|
||||
examine [*<account>[/attrname]]
|
||||
|
||||
Switch:
|
||||
player - examine a Player (same as adding *)
|
||||
account - examine an Account (same as adding *)
|
||||
object - examine an Object (useful when OOC)
|
||||
|
||||
The examine command shows detailed game info about an
|
||||
object and optionally a specific attribute on it.
|
||||
If object is not specified, the current location is examined.
|
||||
|
||||
Append a * before the search string to examine a player.
|
||||
Append a * before the search string to examine an account.
|
||||
|
||||
"""
|
||||
key = "@examine"
|
||||
aliases = ["@ex","ex", "exam", "examine"]
|
||||
locks = "cmd:perm(examine) or perm(Builders)"
|
||||
aliases = ["@ex","exam"]
|
||||
locks = "cmd:perm(examine) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
arg_regex = r"(/\w+?(\s|$))|\s|$"
|
||||
|
||||
player_mode = False
|
||||
account_mode = False
|
||||
|
||||
def list_attribute(self, crop, attr, value):
|
||||
"""
|
||||
|
|
@ -1911,15 +1910,15 @@ class CmdExamine(ObjManipCommand):
|
|||
for sess in obj.sessions.all()))
|
||||
if hasattr(obj, "email") and obj.email:
|
||||
string += "\n|wEmail|n: |c%s|n" % obj.email
|
||||
if hasattr(obj, "has_player") and obj.has_player:
|
||||
string += "\n|wPlayer|n: |c%s|n" % obj.player.name
|
||||
perms = obj.player.permissions.all()
|
||||
if obj.player.is_superuser:
|
||||
if hasattr(obj, "has_account") and obj.has_account:
|
||||
string += "\n|wAccount|n: |c%s|n" % obj.account.name
|
||||
perms = obj.account.permissions.all()
|
||||
if obj.account.is_superuser:
|
||||
perms = ["<Superuser>"]
|
||||
elif not perms:
|
||||
perms = ["<None>"]
|
||||
string += "\n|wPlayer Perms|n: %s" % (", ".join(perms))
|
||||
if obj.player.attributes.has("_quell"):
|
||||
string += "\n|wAccount Perms|n: %s" % (", ".join(perms))
|
||||
if obj.account.attributes.has("_quell"):
|
||||
string += " |r(quelled)|n"
|
||||
string += "\n|wTypeclass|n: %s (%s)" % (obj.typename,
|
||||
obj.typeclass_path)
|
||||
|
|
@ -1962,16 +1961,16 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
# this gets all components of the currently merged set
|
||||
all_cmdsets = [(cmdset.key, cmdset) for cmdset in avail_cmdset.merged_from]
|
||||
# we always at least try to add player- and session sets since these are ignored
|
||||
# we always at least try to add account- and session sets since these are ignored
|
||||
# if we merge on the object level.
|
||||
if hasattr(obj, "player") and obj.player:
|
||||
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.player.cmdset.all()])
|
||||
if hasattr(obj, "account") and obj.account:
|
||||
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.account.cmdset.all()])
|
||||
if obj.sessions.count():
|
||||
# if there are more sessions than one on objects it's because of multisession mode 3.
|
||||
# we only show the first session's cmdset here (it is -in principle- possible that
|
||||
# different sessions have different cmdsets but for admins who want such madness
|
||||
# it is better that they overload with their own CmdExamine to handle it).
|
||||
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.player.sessions.all()[0].cmdset.all()])
|
||||
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.account.sessions.all()[0].cmdset.all()])
|
||||
else:
|
||||
try:
|
||||
# we have to protect this since many objects don't have sessions.
|
||||
|
|
@ -2012,7 +2011,7 @@ class CmdExamine(ObjManipCommand):
|
|||
for content in obj.contents:
|
||||
if content.destination:
|
||||
exits.append(content)
|
||||
elif content.player:
|
||||
elif content.account:
|
||||
pobjs.append(content)
|
||||
else:
|
||||
things.append(content)
|
||||
|
|
@ -2052,7 +2051,7 @@ class CmdExamine(ObjManipCommand):
|
|||
self.msg(caller.at_look(obj))
|
||||
return
|
||||
# using callback for printing result whenever function returns.
|
||||
get_and_merge_cmdsets(obj, self.session, self.player, obj, "object", self.raw_string).addCallback(get_cmdset_callback)
|
||||
get_and_merge_cmdsets(obj, self.session, self.account, obj, "object", self.raw_string).addCallback(get_cmdset_callback)
|
||||
else:
|
||||
self.msg("You need to supply a target to examine.")
|
||||
return
|
||||
|
|
@ -2064,13 +2063,13 @@ class CmdExamine(ObjManipCommand):
|
|||
obj_name = objdef['name']
|
||||
obj_attrs = objdef['attrs']
|
||||
|
||||
self.player_mode = utils.inherits_from(caller, "evennia.players.players.DefaultPlayer") or \
|
||||
"player" in self.switches or obj_name.startswith('*')
|
||||
if self.player_mode:
|
||||
self.account_mode = utils.inherits_from(caller, "evennia.accounts.accounts.DefaultAccount") or \
|
||||
"account" in self.switches or obj_name.startswith('*')
|
||||
if self.account_mode:
|
||||
try:
|
||||
obj = caller.search_player(obj_name.lstrip('*'))
|
||||
obj = caller.search_account(obj_name.lstrip('*'))
|
||||
except AttributeError:
|
||||
# this means we are calling examine from a player object
|
||||
# this means we are calling examine from an account object
|
||||
obj = caller.search(obj_name.lstrip('*'), search_object = 'object' in self.switches)
|
||||
else:
|
||||
obj = caller.search(obj_name)
|
||||
|
|
@ -2090,12 +2089,12 @@ class CmdExamine(ObjManipCommand):
|
|||
else:
|
||||
if obj.sessions.count():
|
||||
mergemode = "session"
|
||||
elif self.player_mode:
|
||||
mergemode = "player"
|
||||
elif self.account_mode:
|
||||
mergemode = "account"
|
||||
else:
|
||||
mergemode = "object"
|
||||
# using callback to print results whenever function returns.
|
||||
get_and_merge_cmdsets(obj, self.session, self.player, obj, mergemode, self.raw_string).addCallback(get_cmdset_callback)
|
||||
get_and_merge_cmdsets(obj, self.session, self.account, obj, mergemode, self.raw_string).addCallback(get_cmdset_callback)
|
||||
|
||||
|
||||
class CmdFind(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -2103,7 +2102,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
|
|||
search the database for objects
|
||||
|
||||
Usage:
|
||||
@find[/switches] <name or dbref or *player> [= dbrefmin[-dbrefmax]]
|
||||
@find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]]
|
||||
|
||||
Switches:
|
||||
room - only look for rooms (location=None)
|
||||
|
|
@ -2112,15 +2111,15 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
|
|||
exact- only exact matches are returned.
|
||||
|
||||
Searches the database for an object of a particular name or exact #dbref.
|
||||
Use *playername to search for a player. The switches allows for
|
||||
Use *accountname to search for an account. The switches allows for
|
||||
limiting object matches to certain game entities. Dbrefmin and dbrefmax
|
||||
limits matches to within the given dbrefs range, or above/below if only
|
||||
one is given.
|
||||
"""
|
||||
|
||||
key = "@find"
|
||||
aliases = "find, @search, search, @locate, locate"
|
||||
locks = "cmd:perm(find) or perm(Builders)"
|
||||
aliases = "@search, @locate"
|
||||
locks = "cmd:perm(find) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -2149,22 +2148,22 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
|
|||
high = max(low, high)
|
||||
|
||||
is_dbref = utils.dbref(searchstring)
|
||||
is_player = searchstring.startswith("*")
|
||||
is_account = searchstring.startswith("*")
|
||||
|
||||
restrictions = ""
|
||||
if self.switches:
|
||||
restrictions = ", %s" % (",".join(self.switches))
|
||||
|
||||
if is_dbref or is_player:
|
||||
if is_dbref or is_account:
|
||||
|
||||
if is_dbref:
|
||||
# a dbref search
|
||||
result = caller.search(searchstring, global_search=True, quiet=True)
|
||||
string = "|wExact dbref match|n(#%i-#%i%s):" % (low, high, restrictions)
|
||||
else:
|
||||
# a player search
|
||||
# an account search
|
||||
searchstring = searchstring.lstrip("*")
|
||||
result = caller.search_player(searchstring, quiet=True)
|
||||
result = caller.search_account(searchstring, quiet=True)
|
||||
string = "|wMatch|n(#%i-#%i%s):" % (low, high, restrictions)
|
||||
|
||||
if "room" in switches:
|
||||
|
|
@ -2182,7 +2181,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
|
|||
result=result[0]
|
||||
string += "\n|g %s - %s|n" % (result.get_display_name(caller), result.path)
|
||||
else:
|
||||
# Not a player/dbref search but a wider search; build a queryset.
|
||||
# Not an account/dbref search but a wider search; build a queryset.
|
||||
# Searchs for key and aliases
|
||||
if "exact" in switches:
|
||||
keyquery = Q(db_key__iexact=searchstring, id__gte=low, id__lte=high)
|
||||
|
|
@ -2251,7 +2250,7 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS):
|
|||
is teleported to the target location. """
|
||||
key = "@tel"
|
||||
aliases = "@teleport"
|
||||
locks = "cmd:perm(teleport) or perm(Builders)"
|
||||
locks = "cmd:perm(teleport) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -2275,10 +2274,10 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS):
|
|||
if not obj_to_teleport:
|
||||
caller.msg("Did not find object to teleport.")
|
||||
return
|
||||
if obj_to_teleport.has_player:
|
||||
if obj_to_teleport.has_account:
|
||||
caller.msg("Cannot teleport a puppeted object "
|
||||
"(%s, puppeted by %s) to a None-location." % (
|
||||
obj_to_teleport.key, obj_to_teleport.player))
|
||||
obj_to_teleport.key, obj_to_teleport.account))
|
||||
return
|
||||
caller.msg("Teleported %s -> None-location." % obj_to_teleport)
|
||||
if obj_to_teleport.location and not tel_quietly:
|
||||
|
|
@ -2352,7 +2351,7 @@ class CmdScript(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@script"
|
||||
aliases = "@addscript"
|
||||
locks = "cmd:perm(script) or perm(Builders)"
|
||||
locks = "cmd:perm(script) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -2453,7 +2452,7 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@tag"
|
||||
aliases = ["@tags"]
|
||||
locks = "cmd:perm(tag) or perm(Builders)"
|
||||
locks = "cmd:perm(tag) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
arg_regex = r"(/\w+?(\s|$))|\s|$"
|
||||
|
||||
|
|
@ -2593,8 +2592,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
|
||||
key = "@spawn"
|
||||
aliases = ["spawn"]
|
||||
locks = "cmd:perm(spawn) or perm(Builders)"
|
||||
locks = "cmd:perm(spawn) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -2635,8 +2633,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
elif isinstance(prototype, dict):
|
||||
# we got the prototype on the command line. We must make sure to not allow
|
||||
# the 'exec' key unless we are immortals or higher.
|
||||
if "exec" in prototype and not self.caller.check_permstring("Immortals"):
|
||||
# the 'exec' key unless we are developers or higher.
|
||||
if "exec" in prototype and not self.caller.check_permstring("Developer"):
|
||||
self.caller.msg("Spawn aborted: You don't have access to use the 'exec' prototype key.")
|
||||
return
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
"""
|
||||
|
||||
This is the cmdset for Player (OOC) commands. These are
|
||||
stored on the Player object and should thus be able to handle getting
|
||||
a Player object as caller rather than a Character.
|
||||
This is the cmdset for Account (OOC) commands. These are
|
||||
stored on the Account object and should thus be able to handle getting
|
||||
an Account object as caller rather than a Character.
|
||||
|
||||
Note - in order for session-rerouting (in MULTISESSION_MODE=2) to
|
||||
function, all commands in this cmdset should use the self.msg()
|
||||
|
|
@ -11,33 +11,33 @@ command method rather than caller.msg().
|
|||
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.default import help, comms, admin, system
|
||||
from evennia.commands.default import building, player
|
||||
from evennia.commands.default import building, account
|
||||
|
||||
|
||||
class PlayerCmdSet(CmdSet):
|
||||
class AccountCmdSet(CmdSet):
|
||||
"""
|
||||
Implements the player command set.
|
||||
Implements the account command set.
|
||||
"""
|
||||
|
||||
key = "DefaultPlayer"
|
||||
key = "DefaultAccount"
|
||||
priority = -10
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
"Populates the cmdset"
|
||||
|
||||
# Player-specific commands
|
||||
self.add(player.CmdOOCLook())
|
||||
self.add(player.CmdIC())
|
||||
self.add(player.CmdOOC())
|
||||
self.add(player.CmdCharCreate())
|
||||
self.add(player.CmdCharDelete())
|
||||
#self.add(player.CmdSessions())
|
||||
self.add(player.CmdWho())
|
||||
self.add(player.CmdOption())
|
||||
self.add(player.CmdQuit())
|
||||
self.add(player.CmdPassword())
|
||||
self.add(player.CmdColorTest())
|
||||
self.add(player.CmdQuell())
|
||||
# Account-specific commands
|
||||
self.add(account.CmdOOCLook())
|
||||
self.add(account.CmdIC())
|
||||
self.add(account.CmdOOC())
|
||||
self.add(account.CmdCharCreate())
|
||||
self.add(account.CmdCharDelete())
|
||||
#self.add(account.CmdSessions())
|
||||
self.add(account.CmdWho())
|
||||
self.add(account.CmdOption())
|
||||
self.add(account.CmdQuit())
|
||||
self.add(account.CmdPassword())
|
||||
self.add(account.CmdColorTest())
|
||||
self.add(account.CmdQuell())
|
||||
|
||||
# testing
|
||||
self.add(building.CmdExamine())
|
||||
|
|
@ -52,7 +52,7 @@ class PlayerCmdSet(CmdSet):
|
|||
self.add(system.CmdPy())
|
||||
|
||||
# Admin commands
|
||||
self.add(admin.CmdDelPlayer())
|
||||
self.add(admin.CmdDelAccount())
|
||||
self.add(admin.CmdNewPassword())
|
||||
|
||||
# Comm commands
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
"""
|
||||
This module ties together all the commands default Character objects have
|
||||
available (i.e. IC commands). Note that some commands, such as
|
||||
communication-commands are instead put on the player level, in the
|
||||
Player cmdset. Player commands remain available also to Characters.
|
||||
communication-commands are instead put on the account level, in the
|
||||
Account cmdset. Account commands remain available also to Characters.
|
||||
"""
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.default import general, help, admin, system
|
||||
|
|
@ -25,7 +25,7 @@ class CharacterCmdSet(CmdSet):
|
|||
self.add(general.CmdInventory())
|
||||
self.add(general.CmdPose())
|
||||
self.add(general.CmdNick())
|
||||
self.add(general.CmdDesc())
|
||||
self.add(general.CmdSetDesc())
|
||||
self.add(general.CmdGet())
|
||||
self.add(general.CmdDrop())
|
||||
self.add(general.CmdGive())
|
||||
|
|
@ -41,7 +41,7 @@ class CharacterCmdSet(CmdSet):
|
|||
self.add(system.CmdPy())
|
||||
self.add(system.CmdScripts())
|
||||
self.add(system.CmdObjects())
|
||||
self.add(system.CmdPlayers())
|
||||
self.add(system.CmdAccounts())
|
||||
self.add(system.CmdService())
|
||||
self.add(system.CmdAbout())
|
||||
self.add(system.CmdTime())
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
This module stores session-level commands.
|
||||
"""
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.default import player
|
||||
from evennia.commands.default import account
|
||||
|
||||
class SessionCmdSet(CmdSet):
|
||||
"""
|
||||
|
|
@ -13,4 +13,4 @@ class SessionCmdSet(CmdSet):
|
|||
|
||||
def at_cmdset_creation(self):
|
||||
"Populate the cmdset"
|
||||
self.add(player.CmdSessions())
|
||||
self.add(account.CmdSessions())
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
Comsystem command module.
|
||||
|
||||
Comm commands are OOC commands and intended to be made available to
|
||||
the Player at all times (they go into the PlayerCmdSet). So we
|
||||
make sure to homogenize self.caller to always be the player object
|
||||
the Account at all times (they go into the AccountCmdSet). So we
|
||||
make sure to homogenize self.caller to always be the account object
|
||||
for easy handling.
|
||||
|
||||
"""
|
||||
from past.builtins import cmp
|
||||
from django.conf import settings
|
||||
from evennia.comms.models import ChannelDB, Msg
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.players import bots
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.accounts import bots
|
||||
from evennia.comms.channelhandler import CHANNELHANDLER
|
||||
from evennia.locks.lockhandler import LockException
|
||||
from evennia.utils import create, utils, evtable
|
||||
|
|
@ -69,14 +69,14 @@ class CmdAddCom(COMMAND_DEFAULT_CLASS):
|
|||
locks = "cmd:not pperm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement the command"""
|
||||
|
||||
caller = self.caller
|
||||
args = self.args
|
||||
player = caller
|
||||
account = caller
|
||||
|
||||
if not args:
|
||||
self.msg("Usage: addcom [alias =] channelname.")
|
||||
|
|
@ -96,21 +96,21 @@ class CmdAddCom(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
# check permissions
|
||||
if not channel.access(player, 'listen'):
|
||||
if not channel.access(account, 'listen'):
|
||||
self.msg("%s: You are not allowed to listen to this channel." % channel.key)
|
||||
return
|
||||
|
||||
string = ""
|
||||
if not channel.has_connection(player):
|
||||
if not channel.has_connection(account):
|
||||
# we want to connect as well.
|
||||
if not channel.connect(player):
|
||||
# if this would have returned True, the player is connected
|
||||
if not channel.connect(account):
|
||||
# if this would have returned True, the account is connected
|
||||
self.msg("%s: You are not allowed to join this channel." % channel.key)
|
||||
return
|
||||
else:
|
||||
string += "You now listen to the channel %s. " % channel.key
|
||||
else:
|
||||
if channel.unmute(player):
|
||||
if channel.unmute(account):
|
||||
string += "You unmute channel %s." % channel.key
|
||||
else:
|
||||
string += "You are already connected to channel %s." % channel.key
|
||||
|
|
@ -145,13 +145,13 @@ class CmdDelCom(COMMAND_DEFAULT_CLASS):
|
|||
locks = "cmd:not perm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implementing the command. """
|
||||
|
||||
caller = self.caller
|
||||
player = caller
|
||||
account = caller
|
||||
|
||||
if not self.args:
|
||||
self.msg("Usage: delcom <alias or channel>")
|
||||
|
|
@ -161,7 +161,7 @@ class CmdDelCom(COMMAND_DEFAULT_CLASS):
|
|||
channel = find_channel(caller, ostring, silent=True, noaliases=True)
|
||||
if channel:
|
||||
# we have given a channel name - unsubscribe
|
||||
if not channel.has_connection(player):
|
||||
if not channel.has_connection(account):
|
||||
self.msg("You are not listening to that channel.")
|
||||
return
|
||||
chkey = channel.key.lower()
|
||||
|
|
@ -171,7 +171,7 @@ class CmdDelCom(COMMAND_DEFAULT_CLASS):
|
|||
for nick in [nick for nick in make_iter(caller.nicks.get(category="channel", return_obj=True))
|
||||
if nick and nick.pk and nick.value[3].lower() == chkey]:
|
||||
nick.delete()
|
||||
disconnect = channel.disconnect(player)
|
||||
disconnect = channel.disconnect(account)
|
||||
if disconnect:
|
||||
wipednicks = " Eventual aliases were removed." if delnicks else ""
|
||||
self.msg("You stop listening to channel '%s'.%s" % (channel.key, wipednicks))
|
||||
|
|
@ -209,7 +209,7 @@ class CmdAllCom(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Runs the function"""
|
||||
|
|
@ -268,12 +268,12 @@ class CmdChannels(COMMAND_DEFAULT_CLASS):
|
|||
Use addcom/delcom to join and leave channels
|
||||
"""
|
||||
key = "@channels"
|
||||
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
|
||||
aliases = ["@clist", "comlist", "chanlist", "channellist", "all channels"]
|
||||
help_category = "Comms"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement function"""
|
||||
|
|
@ -345,7 +345,7 @@ class CmdCdestroy(COMMAND_DEFAULT_CLASS):
|
|||
locks = "cmd: not pperm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Destroy objects cleanly."""
|
||||
|
|
@ -372,15 +372,15 @@ class CmdCdestroy(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
class CmdCBoot(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
kick a player from a channel you control
|
||||
kick an account from a channel you control
|
||||
|
||||
Usage:
|
||||
@cboot[/quiet] <channel> = <player> [:reason]
|
||||
@cboot[/quiet] <channel> = <account> [:reason]
|
||||
|
||||
Switches:
|
||||
quiet - don't notify the channel
|
||||
|
||||
Kicks a player or object from a channel you control.
|
||||
Kicks an account or object from a channel you control.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -389,13 +389,13 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""implement the function"""
|
||||
|
||||
if not self.args or not self.rhs:
|
||||
string = "Usage: @cboot[/quiet] <channel> = <player> [:reason]"
|
||||
string = "Usage: @cboot[/quiet] <channel> = <account> [:reason]"
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
|
|
@ -404,12 +404,12 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
reason = ""
|
||||
if ":" in self.rhs:
|
||||
playername, reason = self.rhs.rsplit(":", 1)
|
||||
searchstring = playername.lstrip('*')
|
||||
accountname, reason = self.rhs.rsplit(":", 1)
|
||||
searchstring = accountname.lstrip('*')
|
||||
else:
|
||||
searchstring = self.rhs.lstrip('*')
|
||||
player = self.caller.search(searchstring, player=True)
|
||||
if not player:
|
||||
account = self.caller.search(searchstring, account=True)
|
||||
if not account:
|
||||
return
|
||||
if reason:
|
||||
reason = " (reason: %s)" % reason
|
||||
|
|
@ -417,20 +417,20 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
|
|||
string = "You don't control this channel."
|
||||
self.msg(string)
|
||||
return
|
||||
if player not in channel.db_subscriptions.all():
|
||||
string = "Player %s is not connected to channel %s." % (player.key, channel.key)
|
||||
if account not in channel.db_subscriptions.all():
|
||||
string = "Account %s is not connected to channel %s." % (account.key, channel.key)
|
||||
self.msg(string)
|
||||
return
|
||||
if "quiet" not in self.switches:
|
||||
string = "%s boots %s from channel.%s" % (self.caller, player.key, reason)
|
||||
string = "%s boots %s from channel.%s" % (self.caller, account.key, reason)
|
||||
channel.msg(string)
|
||||
# find all player's nicks linked to this channel and delete them
|
||||
# find all account's nicks linked to this channel and delete them
|
||||
for nick in [nick for nick in
|
||||
player.character.nicks.get(category="channel") or []
|
||||
account.character.nicks.get(category="channel") or []
|
||||
if nick.value[3].lower() == channel.key]:
|
||||
nick.delete()
|
||||
# disconnect player
|
||||
channel.disconnect(player)
|
||||
# disconnect account
|
||||
channel.disconnect(account)
|
||||
CHANNELHANDLER.update()
|
||||
|
||||
|
||||
|
|
@ -453,11 +453,11 @@ class CmdCemit(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@cemit"
|
||||
aliases = ["@cmsg"]
|
||||
locks = "cmd: not pperm(channel_banned) and pperm(Players)"
|
||||
locks = "cmd: not pperm(channel_banned) and pperm(Account)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement function"""
|
||||
|
|
@ -496,7 +496,7 @@ class CmdCWho(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""implement function"""
|
||||
|
|
@ -530,11 +530,11 @@ class CmdChannelCreate(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@ccreate"
|
||||
aliases = "channelcreate"
|
||||
locks = "cmd:not pperm(channel_banned) and pperm(Players)"
|
||||
locks = "cmd:not pperm(channel_banned) and pperm(Account)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement the command"""
|
||||
|
|
@ -587,7 +587,7 @@ class CmdClock(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""run the function"""
|
||||
|
|
@ -639,7 +639,7 @@ class CmdCdesc(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement command"""
|
||||
|
|
@ -666,10 +666,10 @@ class CmdCdesc(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
class CmdPage(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
send a private message to another player
|
||||
send a private message to another account
|
||||
|
||||
Usage:
|
||||
page[/switches] [<player>,<player>,... = <message>]
|
||||
page[/switches] [<account>,<account>,... = <message>]
|
||||
tell ''
|
||||
page <number>
|
||||
|
||||
|
|
@ -687,12 +687,12 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
player_caller = True
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement function using the Msg methods"""
|
||||
|
||||
# Since player_caller is set above, this will be a Player.
|
||||
# Since account_caller is set above, this will be an Account.
|
||||
caller = self.caller
|
||||
|
||||
# get the messages we've sent (not to channels)
|
||||
|
|
@ -718,7 +718,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
|
|||
try:
|
||||
number = int(self.args)
|
||||
except ValueError:
|
||||
self.msg("Usage: tell [<player> = msg]")
|
||||
self.msg("Usage: tell [<account> = msg]")
|
||||
return
|
||||
|
||||
if len(pages) > number:
|
||||
|
|
@ -767,7 +767,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
|
|||
self.msg("Noone found to page.")
|
||||
return
|
||||
|
||||
header = "|wPlayer|n |c%s|n |wpages:|n" % caller.key
|
||||
header = "|wAccount|n |c%s|n |wpages:|n" % caller.key
|
||||
message = self.rhs
|
||||
|
||||
# if message begins with a :, we assume it is a 'page-pose'
|
||||
|
|
@ -778,7 +778,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
|
|||
create.create_message(caller, message,
|
||||
receivers=recobjs)
|
||||
|
||||
# tell the players they got a message.
|
||||
# tell the accounts they got a message.
|
||||
received = []
|
||||
rstrings = []
|
||||
for pobj in recobjs:
|
||||
|
|
@ -805,7 +805,7 @@ def _list_bots():
|
|||
bots (str): A table of bots or an error message.
|
||||
|
||||
"""
|
||||
ircbots = [bot for bot in PlayerDB.objects.filter(db_is_bot=True, username__startswith="ircbot-")]
|
||||
ircbots = [bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="ircbot-")]
|
||||
if ircbots:
|
||||
from evennia.utils.evtable import EvTable
|
||||
table = EvTable("|w#dbref|n", "|wbotname|n", "|wev-channel|n",
|
||||
|
|
@ -836,7 +836,7 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
Example:
|
||||
@irc2chan myircchan = irc.dalnet.net 6667 #mychannel evennia-bot
|
||||
@irc2chan public = irc.freenode.net 6667 #evgaming #evbot:players.mybot.MyBot
|
||||
@irc2chan public = irc.freenode.net 6667 #evgaming #evbot:accounts.mybot.MyBot
|
||||
|
||||
This creates an IRC bot that connects to a given IRC network and
|
||||
channel. If a custom typeclass path is given, this will be used
|
||||
|
|
@ -850,7 +850,7 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
|
||||
key = "@irc2chan"
|
||||
locks = "cmd:serversetting(IRC_ENABLED) and pperm(Immortals)"
|
||||
locks = "cmd:serversetting(IRC_ENABLED) and pperm(Developer)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -868,11 +868,11 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
|
||||
botname = "ircbot-%s" % self.lhs
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, username=botname)
|
||||
matches = AccountDB.objects.filter(db_is_bot=True, username=botname)
|
||||
dbref = utils.dbref(self.lhs)
|
||||
if not matches and dbref:
|
||||
# try dbref match
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, id=dbref)
|
||||
matches = AccountDB.objects.filter(db_is_bot=True, id=dbref)
|
||||
if matches:
|
||||
matches[0].delete()
|
||||
self.msg("IRC connection destroyed.")
|
||||
|
|
@ -906,16 +906,16 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
|
|||
irc_ssl = "ssl" in self.switches
|
||||
|
||||
# create a new bot
|
||||
bot = PlayerDB.objects.filter(username__iexact=botname)
|
||||
bot = AccountDB.objects.filter(username__iexact=botname)
|
||||
if bot:
|
||||
# re-use an existing bot
|
||||
bot = bot[0]
|
||||
if not bot.is_bot:
|
||||
self.msg("Player '%s' already exists and is not a bot." % botname)
|
||||
self.msg("Account '%s' already exists and is not a bot." % botname)
|
||||
return
|
||||
else:
|
||||
try:
|
||||
bot = create.create_player(botname, None, None, typeclass=botclass)
|
||||
bot = create.create_account(botname, None, None, typeclass=botclass)
|
||||
except Exception as err:
|
||||
self.msg("|rError, could not create the bot:|n '%s'." % err)
|
||||
return
|
||||
|
|
@ -943,7 +943,7 @@ class CmdIRCStatus(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
key = "@ircstatus"
|
||||
locks = "cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builders))"
|
||||
locks = "cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -963,7 +963,7 @@ class CmdIRCStatus(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
matches = None
|
||||
if utils.dbref(botname):
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, id=utils.dbref(botname))
|
||||
matches = AccountDB.objects.filter(db_is_bot=True, id=utils.dbref(botname))
|
||||
if not matches:
|
||||
self.msg("No matching IRC-bot found. Use @ircstatus without arguments to list active bots.")
|
||||
return
|
||||
|
|
@ -981,7 +981,7 @@ class CmdIRCStatus(COMMAND_DEFAULT_CLASS):
|
|||
# an asynchronous call.
|
||||
self.caller.msg("Requesting nicklist from %s (%s:%s)." % (channel, network, port))
|
||||
ircbot.get_nicklist(self.caller)
|
||||
elif self.caller.locks.check_lockstring(self.caller, "dummy:perm(ircstatus) or perm(Immortals)"):
|
||||
elif self.caller.locks.check_lockstring(self.caller, "dummy:perm(ircstatus) or perm(Developer)"):
|
||||
# reboot the client
|
||||
self.caller.msg("Forcing a disconnect + reconnect of %s." % chtext)
|
||||
ircbot.reconnect()
|
||||
|
|
@ -1016,7 +1016,7 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
|
||||
key = "@rss2chan"
|
||||
locks = "cmd:serversetting(RSS_ENABLED) and pperm(Immortals)"
|
||||
locks = "cmd:serversetting(RSS_ENABLED) and pperm(Developer)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -1038,7 +1038,7 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
if 'list' in self.switches:
|
||||
# show all connections
|
||||
rssbots = [bot for bot in PlayerDB.objects.filter(db_is_bot=True, username__startswith="rssbot-")]
|
||||
rssbots = [bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="rssbot-")]
|
||||
if rssbots:
|
||||
from evennia.utils.evtable import EvTable
|
||||
table = EvTable("|wdbid|n", "|wupdate rate|n", "|wev-channel",
|
||||
|
|
@ -1052,10 +1052,10 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
|
||||
botname = "rssbot-%s" % self.lhs
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, db_key=botname)
|
||||
matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname)
|
||||
if not matches:
|
||||
# try dbref match
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#"))
|
||||
matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#"))
|
||||
if matches:
|
||||
matches[0].delete()
|
||||
self.msg("RSS connection destroyed.")
|
||||
|
|
@ -1072,14 +1072,14 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
botname = "rssbot-%s" % url
|
||||
# create a new bot
|
||||
bot = PlayerDB.objects.filter(username__iexact=botname)
|
||||
bot = AccountDB.objects.filter(username__iexact=botname)
|
||||
if bot:
|
||||
# re-use existing bot
|
||||
bot = bot[0]
|
||||
if not bot.is_bot:
|
||||
self.msg("Player '%s' already exists and is not a bot." % botname)
|
||||
self.msg("Account '%s' already exists and is not a bot." % botname)
|
||||
return
|
||||
else:
|
||||
bot = create.create_player(botname, None, None, typeclass=bots.RSSBot)
|
||||
bot = create.create_account(botname, None, None, typeclass=bots.RSSBot)
|
||||
bot.start(ev_channel=channel, rss_url=url, rss_rate=10)
|
||||
self.msg("RSS reporter created. Fetching RSS.")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
|||
|
||||
# limit symbol import for API
|
||||
__all__ = ("CmdHome", "CmdLook", "CmdNick",
|
||||
"CmdInventory", "CmdGet", "CmdDrop", "CmdGive",
|
||||
"CmdInventory", "CmdSetDesc", "CmdGet", "CmdDrop", "CmdGive",
|
||||
"CmdSay", "CmdWhisper", "CmdPose", "CmdAccess")
|
||||
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ class CmdHome(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
|
||||
key = "home"
|
||||
locks = "cmd:perm(home) or perm(Builders)"
|
||||
locks = "cmd:perm(home) or perm(Builder)"
|
||||
arg_regex = r"$"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -47,7 +47,7 @@ class CmdLook(COMMAND_DEFAULT_CLASS):
|
|||
Usage:
|
||||
look
|
||||
look <obj>
|
||||
look *<player>
|
||||
look *<account>
|
||||
|
||||
Observes your location or objects in your vicinity.
|
||||
"""
|
||||
|
|
@ -86,7 +86,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
|
|||
Switches:
|
||||
inputline - replace on the inputline (default)
|
||||
object - replace on object-lookup
|
||||
player - replace on player-lookup
|
||||
account - replace on account-lookup
|
||||
delete - remove nick by name or by index given by /list
|
||||
clearall - clear all nicks
|
||||
list - show all defined aliases (also "nicks" works)
|
||||
|
|
@ -113,7 +113,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
key = "nick"
|
||||
aliases = ["nickname", "nicks", "@nick", "@nicks", "alias"]
|
||||
aliases = ["nickname", "nicks", "alias"]
|
||||
locks = "cmd:all()"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -121,7 +121,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
caller = self.caller
|
||||
switches = self.switches
|
||||
nicktypes = [switch for switch in switches if switch in ("object", "player", "inputline")] or ["inputline"]
|
||||
nicktypes = [switch for switch in switches if switch in ("object", "account", "inputline")] or ["inputline"]
|
||||
|
||||
nicklist = utils.make_iter(caller.nicks.get(return_obj=True) or [])
|
||||
|
||||
|
|
@ -358,18 +358,18 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
|
|||
to_give.at_give(caller, target)
|
||||
|
||||
|
||||
class CmdDesc(COMMAND_DEFAULT_CLASS):
|
||||
class CmdSetDesc(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
describe yourself
|
||||
|
||||
Usage:
|
||||
desc <description>
|
||||
setdesc <description>
|
||||
|
||||
Add a description to yourself. This
|
||||
will be visible to people when they
|
||||
look at you.
|
||||
"""
|
||||
key = "desc"
|
||||
key = "setdesc"
|
||||
locks = "cmd:all()"
|
||||
arg_regex = r"\s|$"
|
||||
|
||||
|
|
@ -417,7 +417,7 @@ class CmdSay(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
# Call the at_after_say hook on the character
|
||||
caller.at_after_say(speech)
|
||||
caller.at_say(speech)
|
||||
|
||||
class CmdWhisper(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
|
|
@ -439,7 +439,7 @@ class CmdWhisper(COMMAND_DEFAULT_CLASS):
|
|||
caller = self.caller
|
||||
|
||||
if not self.lhs or not self.rhs:
|
||||
caller.msg("Usage: whisper <player> = <message>")
|
||||
caller.msg("Usage: whisper <account> = <message>")
|
||||
return
|
||||
|
||||
receiver = caller.search(self.lhs)
|
||||
|
|
@ -453,14 +453,14 @@ class CmdWhisper(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
speech = self.rhs
|
||||
# Call a hook to change the speech before whispering
|
||||
speech = caller.at_before_whisper(receiver, speech)
|
||||
speech = caller.at_before_say(speech, whisper=True, receiver=receiver)
|
||||
|
||||
# If the speech is empty, abort the command
|
||||
if not speech:
|
||||
return
|
||||
|
||||
# Call the at_after_whisper hook for feedback
|
||||
caller.at_after_whisper(receiver, speech)
|
||||
caller.at_say(speech, receiver=receiver, whisper=True)
|
||||
|
||||
|
||||
class CmdPose(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -529,15 +529,15 @@ class CmdAccess(COMMAND_DEFAULT_CLASS):
|
|||
hierarchy_full = settings.PERMISSION_HIERARCHY
|
||||
string = "\n|wPermission Hierarchy|n (climbing):\n %s" % ", ".join(hierarchy_full)
|
||||
|
||||
if self.caller.player.is_superuser:
|
||||
if self.caller.account.is_superuser:
|
||||
cperms = "<Superuser>"
|
||||
pperms = "<Superuser>"
|
||||
else:
|
||||
cperms = ", ".join(caller.permissions.all())
|
||||
pperms = ", ".join(caller.player.permissions.all())
|
||||
pperms = ", ".join(caller.account.permissions.all())
|
||||
|
||||
string += "\n|wYour access|n:"
|
||||
string += "\nCharacter |c%s|n: %s" % (caller.key, cperms)
|
||||
if hasattr(caller, 'player'):
|
||||
string += "\nPlayer |c%s|n: %s" % (caller.player.key, pperms)
|
||||
if hasattr(caller, 'account'):
|
||||
string += "\nAccount |c%s|n: %s" % (caller.account.key, pperms)
|
||||
caller.msg(string)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class CmdHelp(Command):
|
|||
|
||||
if self.session.protocol_key in ("websocket", "ajax/comet"):
|
||||
try:
|
||||
options = self.player.db._saved_webclient_options
|
||||
options = self.account.db._saved_webclient_options
|
||||
if options and options["helppopup"]:
|
||||
usemore = False
|
||||
except KeyError:
|
||||
|
|
@ -134,12 +134,12 @@ class CmdHelp(Command):
|
|||
Helper method. If this return True, the given cmd
|
||||
auto-help will be viewable in the help listing.
|
||||
Override this to easily select what is shown to
|
||||
the player. Note that only commands available
|
||||
the account. Note that only commands available
|
||||
in the caller's merged cmdset are available.
|
||||
|
||||
Args:
|
||||
cmd (Command): Command class from the merged cmdset
|
||||
caller (Character, Player or Session): The current caller
|
||||
caller (Character, Account or Session): The current caller
|
||||
executing the help command.
|
||||
|
||||
"""
|
||||
|
|
@ -300,9 +300,8 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
|
|||
is to let everyone read the help file.
|
||||
|
||||
"""
|
||||
key = "@help"
|
||||
aliases = "@sethelp"
|
||||
locks = "cmd:perm(PlayerHelpers)"
|
||||
key = "@sethelp"
|
||||
locks = "cmd:perm(Helper)"
|
||||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
"""
|
||||
The command template for the default MUX-style command set. There
|
||||
is also an Player/OOC version that makes sure caller is a Player object.
|
||||
is also an Account/OOC version that makes sure caller is an Account object.
|
||||
"""
|
||||
|
||||
from evennia.utils import utils
|
||||
from evennia.commands.command import Command
|
||||
|
||||
# limit symbol import for API
|
||||
__all__ = ("MuxCommand", "MuxPlayerCommand")
|
||||
__all__ = ("MuxCommand", "MuxAccountCommand")
|
||||
|
||||
|
||||
class MuxCommand(Command):
|
||||
|
|
@ -128,17 +128,17 @@ class MuxCommand(Command):
|
|||
self.rhs = rhs
|
||||
self.rhslist = rhslist
|
||||
|
||||
# if the class has the player_caller property set on itself, we make
|
||||
# sure that self.caller is always the player if possible. We also create
|
||||
# if the class has the account_caller property set on itself, we make
|
||||
# sure that self.caller is always the account if possible. We also create
|
||||
# a special property "character" for the puppeted object, if any. This
|
||||
# is convenient for commands defined on the Player only.
|
||||
if hasattr(self, "player_caller") and self.player_caller:
|
||||
# is convenient for commands defined on the Account only.
|
||||
if hasattr(self, "account_caller") and self.account_caller:
|
||||
if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"):
|
||||
# caller is an Object/Character
|
||||
self.character = self.caller
|
||||
self.caller = self.caller.player
|
||||
elif utils.inherits_from(self.caller, "evennia.players.players.DefaultPlayer"):
|
||||
# caller was already a Player
|
||||
self.caller = self.caller.account
|
||||
elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"):
|
||||
# caller was already an Account
|
||||
self.character = self.caller.get_puppet(self.session)
|
||||
else:
|
||||
self.character = None
|
||||
|
|
@ -177,32 +177,32 @@ class MuxCommand(Command):
|
|||
self.caller.msg(string)
|
||||
|
||||
|
||||
class MuxPlayerCommand(MuxCommand):
|
||||
class MuxAccountCommand(MuxCommand):
|
||||
"""
|
||||
This is an on-Player version of the MuxCommand. Since these commands sit
|
||||
on Players rather than on Characters/Objects, we need to check
|
||||
This is an on-Account version of the MuxCommand. Since these commands sit
|
||||
on Accounts rather than on Characters/Objects, we need to check
|
||||
this in the parser.
|
||||
|
||||
Player commands are available also when puppeting a Character, it's
|
||||
Account commands are available also when puppeting a Character, it's
|
||||
just that they are applied with a lower priority and are always
|
||||
available, also when disconnected from a character (i.e. "ooc").
|
||||
|
||||
This class makes sure that caller is always a Player object, while
|
||||
This class makes sure that caller is always an Account object, while
|
||||
creating a new property "character" that is set only if a
|
||||
character is actually attached to this Player and Session.
|
||||
character is actually attached to this Account and Session.
|
||||
"""
|
||||
def parse(self):
|
||||
"""
|
||||
We run the parent parser as usual, then fix the result
|
||||
"""
|
||||
super(MuxPlayerCommand, self).parse()
|
||||
super(MuxAccountCommand, self).parse()
|
||||
|
||||
if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"):
|
||||
# caller is an Object/Character
|
||||
self.character = self.caller
|
||||
self.caller = self.caller.player
|
||||
elif utils.inherits_from(self.caller, "evennia.players.players.DefaultPlayer"):
|
||||
# caller was already a Player
|
||||
self.caller = self.caller.account
|
||||
elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"):
|
||||
# caller was already an Account
|
||||
self.character = self.caller.get_puppet(self.session)
|
||||
else:
|
||||
self.character = None
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ from django.conf import settings
|
|||
from evennia.server.sessionhandler import SESSIONS
|
||||
from evennia.scripts.models import ScriptDB
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.utils import logger, utils, gametime, create
|
||||
from evennia.utils.eveditor import EvEditor
|
||||
from evennia.utils.evtable import EvTable
|
||||
|
|
@ -47,7 +47,7 @@ class CmdReload(COMMAND_DEFAULT_CLASS):
|
|||
@reset to purge) and at_reload() hooks will be called.
|
||||
"""
|
||||
key = "@reload"
|
||||
locks = "cmd:perm(reload) or perm(Immortals)"
|
||||
locks = "cmd:perm(reload) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -83,7 +83,7 @@ class CmdReset(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@reset"
|
||||
aliases = ['@reboot']
|
||||
locks = "cmd:perm(reload) or perm(Immortals)"
|
||||
locks = "cmd:perm(reload) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -105,7 +105,7 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS):
|
|||
Gracefully shut down both Server and Portal.
|
||||
"""
|
||||
key = "@shutdown"
|
||||
locks = "cmd:perm(shutdown) or perm(Immortals)"
|
||||
locks = "cmd:perm(shutdown) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -244,7 +244,7 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@py"
|
||||
aliases = ["!"]
|
||||
locks = "cmd:perm(py) or perm(Immortals)"
|
||||
locks = "cmd:perm(py) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -327,7 +327,7 @@ class CmdScripts(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@scripts"
|
||||
aliases = ["@globalscript", "@listscripts"]
|
||||
locks = "cmd:perm(listscripts) or perm(Wizards)"
|
||||
locks = "cmd:perm(listscripts) or perm(Admin)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -409,7 +409,7 @@ class CmdObjects(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@objects"
|
||||
aliases = ["@listobjects", "@listobjs", '@stats', '@db']
|
||||
locks = "cmd:perm(listobjects) or perm(Builders)"
|
||||
locks = "cmd:perm(listobjects) or perm(Builder)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -455,24 +455,24 @@ class CmdObjects(COMMAND_DEFAULT_CLASS):
|
|||
caller.msg(string)
|
||||
|
||||
|
||||
class CmdPlayers(COMMAND_DEFAULT_CLASS):
|
||||
class CmdAccounts(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
list all registered players
|
||||
list all registered accounts
|
||||
|
||||
Usage:
|
||||
@players [nr]
|
||||
@accounts [nr]
|
||||
|
||||
Lists statistics about the Players registered with the game.
|
||||
It will list the <nr> amount of latest registered players
|
||||
Lists statistics about the Accounts registered with the game.
|
||||
It will list the <nr> amount of latest registered accounts
|
||||
If not given, <nr> defaults to 10.
|
||||
"""
|
||||
key = "@players"
|
||||
aliases = ["@listplayers"]
|
||||
locks = "cmd:perm(listplayers) or perm(Wizards)"
|
||||
key = "@accounts"
|
||||
aliases = ["@listaccounts"]
|
||||
locks = "cmd:perm(listaccounts) or perm(Admin)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
"""List the players"""
|
||||
"""List the accounts"""
|
||||
|
||||
caller = self.caller
|
||||
if self.args and self.args.isdigit():
|
||||
|
|
@ -480,21 +480,21 @@ class CmdPlayers(COMMAND_DEFAULT_CLASS):
|
|||
else:
|
||||
nlim = 10
|
||||
|
||||
nplayers = PlayerDB.objects.count()
|
||||
naccounts = AccountDB.objects.count()
|
||||
|
||||
# typeclass table
|
||||
dbtotals = PlayerDB.objects.object_totals()
|
||||
dbtotals = AccountDB.objects.object_totals()
|
||||
typetable = EvTable("|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l")
|
||||
for path, count in dbtotals.items():
|
||||
typetable.add_row(path, count, "%.2f" % ((float(count) / nplayers) * 100))
|
||||
typetable.add_row(path, count, "%.2f" % ((float(count) / naccounts) * 100))
|
||||
# last N table
|
||||
plyrs = PlayerDB.objects.all().order_by("db_date_created")[max(0, nplayers - nlim):]
|
||||
plyrs = AccountDB.objects.all().order_by("db_date_created")[max(0, naccounts - nlim):]
|
||||
latesttable = EvTable("|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", border="cells", align="l")
|
||||
for ply in plyrs:
|
||||
latesttable.add_row(utils.datetime_format(ply.date_created), ply.dbref, ply.key, ply.path)
|
||||
|
||||
string = "\n|wPlayer typeclass distribution:|n\n%s" % typetable
|
||||
string += "\n|wLast %s Players created:|n\n%s" % (min(nplayers, nlim), latesttable)
|
||||
string = "\n|wAccount typeclass distribution:|n\n%s" % typetable
|
||||
string += "\n|wLast %s Accounts created:|n\n%s" % (min(naccounts, nlim), latesttable)
|
||||
caller.msg(string)
|
||||
|
||||
|
||||
|
|
@ -520,7 +520,7 @@ class CmdService(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
key = "@service"
|
||||
aliases = ["@services"]
|
||||
locks = "cmd:perm(service) or perm(Immortals)"
|
||||
locks = "cmd:perm(service) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -644,7 +644,7 @@ class CmdTime(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@time"
|
||||
aliases = "@uptime"
|
||||
locks = "cmd:perm(time) or perm(Players)"
|
||||
locks = "cmd:perm(time) or perm(Account)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -702,7 +702,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@server"
|
||||
aliases = ["@serverload", "@serverprocess"]
|
||||
locks = "cmd:perm(list) or perm(Immortals)"
|
||||
locks = "cmd:perm(list) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -823,7 +823,7 @@ class CmdTickers(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
key = "@tickers"
|
||||
help_category = "System"
|
||||
locks = "cmd:perm(tickers) or perm(Builders)"
|
||||
locks = "cmd:perm(tickers) or perm(Builder)"
|
||||
|
||||
def func(self):
|
||||
from evennia import TICKER_HANDLER
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from mock import Mock
|
|||
|
||||
from evennia.commands.default.cmdset_character import CharacterCmdSet
|
||||
from evennia.utils.test_resources import EvenniaTest
|
||||
from evennia.commands.default import help, general, system, admin, player, building, batchprocess, comms
|
||||
from evennia.commands.default import help, general, system, admin, account, building, batchprocess, comms
|
||||
from evennia.commands.command import Command, InterruptCommand
|
||||
from evennia.utils import ansi, utils
|
||||
from evennia.server.sessionhandler import SESSIONS
|
||||
|
|
@ -57,11 +57,13 @@ class CommandTest(EvenniaTest):
|
|||
caller = caller if caller else self.char1
|
||||
receiver = receiver if receiver else caller
|
||||
cmdobj.caller = caller
|
||||
cmdobj.cmdstring = cmdstring if cmdstring else cmdobj.key
|
||||
cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key
|
||||
cmdobj.raw_cmdname = cmdobj.cmdname
|
||||
cmdobj.cmdstring = cmdobj.cmdname # deprecated
|
||||
cmdobj.args = args
|
||||
cmdobj.cmdset = cmdset
|
||||
cmdobj.session = SESSIONS.session_from_sessid(1)
|
||||
cmdobj.player = self.player
|
||||
cmdobj.account = self.account
|
||||
cmdobj.raw_string = cmdobj.key + " " + args
|
||||
cmdobj.obj = obj or (caller if caller else self.char1)
|
||||
# test
|
||||
|
|
@ -76,7 +78,7 @@ class CommandTest(EvenniaTest):
|
|||
except InterruptCommand:
|
||||
pass
|
||||
finally:
|
||||
# clean out prettytable sugar. We only operate on text-type
|
||||
# clean out evtable sugar. We only operate on text-type
|
||||
stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True))
|
||||
for name, args, kwargs in receiver.msg.mock_calls]
|
||||
# Get the first element of a tuple if msg received a tuple instead of a string
|
||||
|
|
@ -117,10 +119,10 @@ class TestGeneral(CommandTest):
|
|||
|
||||
def test_nick(self):
|
||||
self.call(general.CmdNick(), "testalias = testaliasedstring1", "Nick 'testalias' mapped to 'testaliasedstring1'.")
|
||||
self.call(general.CmdNick(), "/player testalias = testaliasedstring2", "Nick 'testalias' mapped to 'testaliasedstring2'.")
|
||||
self.call(general.CmdNick(), "/account testalias = testaliasedstring2", "Nick 'testalias' mapped to 'testaliasedstring2'.")
|
||||
self.call(general.CmdNick(), "/object testalias = testaliasedstring3", "Nick 'testalias' mapped to 'testaliasedstring3'.")
|
||||
self.assertEqual(u"testaliasedstring1", self.char1.nicks.get("testalias"))
|
||||
self.assertEqual(u"testaliasedstring2", self.char1.nicks.get("testalias", category="player"))
|
||||
self.assertEqual(u"testaliasedstring2", self.char1.nicks.get("testalias", category="account"))
|
||||
self.assertEqual(u"testaliasedstring3", self.char1.nicks.get("testalias", category="object"))
|
||||
|
||||
def test_get_and_drop(self):
|
||||
|
|
@ -170,54 +172,54 @@ class TestAdmin(CommandTest):
|
|||
self.call(admin.CmdEmit(), "Char2 = Test", "Emitted to Char2:\nTest")
|
||||
|
||||
def test_perm(self):
|
||||
self.call(admin.CmdPerm(), "Obj = Builders", "Permission 'Builders' given to Obj (the Object/Character).")
|
||||
self.call(admin.CmdPerm(), "Char2 = Builders", "Permission 'Builders' given to Char2 (the Object/Character).")
|
||||
self.call(admin.CmdPerm(), "Obj = Builder", "Permission 'Builder' given to Obj (the Object/Character).")
|
||||
self.call(admin.CmdPerm(), "Char2 = Builder", "Permission 'Builder' given to Char2 (the Object/Character).")
|
||||
|
||||
def test_wall(self):
|
||||
self.call(admin.CmdWall(), "Test", "Announcing to all connected players ...")
|
||||
self.call(admin.CmdWall(), "Test", "Announcing to all connected accounts ...")
|
||||
|
||||
def test_ban(self):
|
||||
self.call(admin.CmdBan(), "Char", "NameBan char was added.")
|
||||
|
||||
|
||||
class TestPlayer(CommandTest):
|
||||
class TestAccount(CommandTest):
|
||||
|
||||
def test_ooc_look(self):
|
||||
if settings.MULTISESSION_MODE < 2:
|
||||
self.call(player.CmdOOCLook(), "", "You are outofcharacter (OOC).", caller=self.player)
|
||||
self.call(account.CmdOOCLook(), "", "You are outofcharacter (OOC).", caller=self.account)
|
||||
if settings.MULTISESSION_MODE == 2:
|
||||
self.call(player.CmdOOCLook(), "", "Account TestPlayer (you are OutofCharacter)", caller=self.player)
|
||||
self.call(account.CmdOOCLook(), "", "Account TestAccount (you are OutofCharacter)", caller=self.account)
|
||||
|
||||
def test_ooc(self):
|
||||
self.call(player.CmdOOC(), "", "You go OOC.", caller=self.player)
|
||||
self.call(account.CmdOOC(), "", "You go OOC.", caller=self.account)
|
||||
|
||||
def test_ic(self):
|
||||
self.player.unpuppet_object(self.session)
|
||||
self.call(player.CmdIC(), "Char", "You become Char.", caller=self.player, receiver=self.char1)
|
||||
self.account.unpuppet_object(self.session)
|
||||
self.call(account.CmdIC(), "Char", "You become Char.", caller=self.account, receiver=self.char1)
|
||||
|
||||
def test_password(self):
|
||||
self.call(player.CmdPassword(), "testpassword = testpassword", "Password changed.", caller=self.player)
|
||||
self.call(account.CmdPassword(), "testpassword = testpassword", "Password changed.", caller=self.account)
|
||||
|
||||
def test_option(self):
|
||||
self.call(player.CmdOption(), "", "Client settings", caller=self.player)
|
||||
self.call(account.CmdOption(), "", "Client settings", caller=self.account)
|
||||
|
||||
def test_who(self):
|
||||
self.call(player.CmdWho(), "", "Players:", caller=self.player)
|
||||
self.call(account.CmdWho(), "", "Accounts:", caller=self.account)
|
||||
|
||||
def test_quit(self):
|
||||
self.call(player.CmdQuit(), "", "Quitting. Hope to see you again, soon.", caller=self.player)
|
||||
self.call(account.CmdQuit(), "", "Quitting. Hope to see you again, soon.", caller=self.account)
|
||||
|
||||
def test_sessions(self):
|
||||
self.call(player.CmdSessions(), "", "Your current session(s):", caller=self.player)
|
||||
self.call(account.CmdSessions(), "", "Your current session(s):", caller=self.account)
|
||||
|
||||
def test_color_test(self):
|
||||
self.call(player.CmdColorTest(), "ansi", "ANSI colors:", caller=self.player)
|
||||
self.call(account.CmdColorTest(), "ansi", "ANSI colors:", caller=self.account)
|
||||
|
||||
def test_char_create(self):
|
||||
self.call(player.CmdCharCreate(), "Test1=Test char", "Created new character Test1. Use @ic Test1 to enter the game", caller=self.player)
|
||||
self.call(account.CmdCharCreate(), "Test1=Test char", "Created new character Test1. Use @ic Test1 to enter the game", caller=self.account)
|
||||
|
||||
def test_quell(self):
|
||||
self.call(player.CmdQuell(), "", "Quelling to current puppet's permissions (immortals).", caller=self.player)
|
||||
self.call(account.CmdQuell(), "", "Quelling to current puppet's permissions (developer).", caller=self.account)
|
||||
|
||||
|
||||
class TestBuilding(CommandTest):
|
||||
|
|
@ -272,7 +274,7 @@ class TestBuilding(CommandTest):
|
|||
"Obj changed typeclass from evennia.objects.objects.DefaultObject to evennia.objects.objects.DefaultExit.")
|
||||
|
||||
def test_lock(self):
|
||||
self.call(building.CmdLock(), "Obj = test:perm(Immortals)", "Added lock 'test:perm(Immortals)' to Obj.")
|
||||
self.call(building.CmdLock(), "Obj = test:perm(Developer)", "Added lock 'test:perm(Developer)' to Obj.")
|
||||
|
||||
def test_find(self):
|
||||
self.call(building.CmdFind(), "Room2", "One Match")
|
||||
|
|
@ -288,39 +290,39 @@ class TestComms(CommandTest):
|
|||
|
||||
def setUp(self):
|
||||
super(CommandTest, self).setUp()
|
||||
self.call(comms.CmdChannelCreate(), "testchan;test=Test Channel", "Created channel testchan and connected to it.", receiver=self.player)
|
||||
self.call(comms.CmdChannelCreate(), "testchan;test=Test Channel", "Created channel testchan and connected to it.", receiver=self.account)
|
||||
|
||||
def test_toggle_com(self):
|
||||
self.call(comms.CmdAddCom(), "tc = testchan", "You are already connected to channel testchan. You can now", receiver=self.player)
|
||||
self.call(comms.CmdDelCom(), "tc", "Your alias 'tc' for channel testchan was cleared.", receiver=self.player)
|
||||
self.call(comms.CmdAddCom(), "tc = testchan", "You are already connected to channel testchan. You can now", receiver=self.account)
|
||||
self.call(comms.CmdDelCom(), "tc", "Your alias 'tc' for channel testchan was cleared.", receiver=self.account)
|
||||
|
||||
def test_channels(self):
|
||||
self.call(comms.CmdChannels(), "" ,"Available channels (use comlist,addcom and delcom to manage", receiver=self.player)
|
||||
self.call(comms.CmdChannels(), "" ,"Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
|
||||
|
||||
def test_all_com(self):
|
||||
self.call(comms.CmdAllCom(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.player)
|
||||
self.call(comms.CmdAllCom(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
|
||||
|
||||
def test_clock(self):
|
||||
self.call(comms.CmdClock(), "testchan=send:all()", "Lock(s) applied. Current locks on testchan:", receiver=self.player)
|
||||
self.call(comms.CmdClock(), "testchan=send:all()", "Lock(s) applied. Current locks on testchan:", receiver=self.account)
|
||||
|
||||
def test_cdesc(self):
|
||||
self.call(comms.CmdCdesc(), "testchan = Test Channel", "Description of channel 'testchan' set to 'Test Channel'.", receiver=self.player)
|
||||
self.call(comms.CmdCdesc(), "testchan = Test Channel", "Description of channel 'testchan' set to 'Test Channel'.", receiver=self.account)
|
||||
|
||||
def test_cemit(self):
|
||||
self.call(comms.CmdCemit(), "testchan = Test Message", "[testchan] Test Message|Sent to channel testchan: Test Message", receiver=self.player)
|
||||
self.call(comms.CmdCemit(), "testchan = Test Message", "[testchan] Test Message|Sent to channel testchan: Test Message", receiver=self.account)
|
||||
|
||||
def test_cwho(self):
|
||||
self.call(comms.CmdCWho(), "testchan", "Channel subscriptions\ntestchan:\n TestPlayer", receiver=self.player)
|
||||
self.call(comms.CmdCWho(), "testchan", "Channel subscriptions\ntestchan:\n TestAccount", receiver=self.account)
|
||||
|
||||
def test_page(self):
|
||||
self.call(comms.CmdPage(), "TestPlayer2 = Test", "TestPlayer2 is offline. They will see your message if they list their pages later.|You paged TestPlayer2 with: 'Test'.", receiver=self.player)
|
||||
self.call(comms.CmdPage(), "TestAccount2 = Test", "TestAccount2 is offline. They will see your message if they list their pages later.|You paged TestAccount2 with: 'Test'.", receiver=self.account)
|
||||
|
||||
def test_cboot(self):
|
||||
# No one else connected to boot
|
||||
self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] <channel> = <player> [:reason]", receiver=self.player)
|
||||
self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] <channel> = <account> [:reason]", receiver=self.account)
|
||||
|
||||
def test_cdestroy(self):
|
||||
self.call(comms.CmdCdestroy(), "testchan" ,"[testchan] TestPlayer: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.", receiver=self.player)
|
||||
self.call(comms.CmdCdestroy(), "testchan" ,"[testchan] TestAccount: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.", receiver=self.account)
|
||||
|
||||
|
||||
class TestBatchProcess(CommandTest):
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from collections import defaultdict
|
|||
from random import getrandbits
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.server.models import ServerConfig
|
||||
from evennia.comms.models import ChannelDB
|
||||
|
|
@ -25,7 +25,7 @@ MULTISESSION_MODE = settings.MULTISESSION_MODE
|
|||
CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
|
||||
|
||||
# Helper function to throttle failed connection attempts.
|
||||
# This can easily be used to limit player creation too,
|
||||
# This can easily be used to limit account creation too,
|
||||
# (just supply a different storage dictionary), but this
|
||||
# would also block dummyrunner, so it's not added as default.
|
||||
|
||||
|
|
@ -77,17 +77,17 @@ def _throttle(session, maxlim=None, timeout=None, storage=_LATEST_FAILED_LOGINS)
|
|||
return False
|
||||
|
||||
|
||||
def create_guest_player(session):
|
||||
def create_guest_account(session):
|
||||
"""
|
||||
Creates a guest player/character for this session, if one is available.
|
||||
Creates a guest account/character for this session, if one is available.
|
||||
|
||||
Args:
|
||||
session (Session): the session which will use the guest player/character.
|
||||
session (Session): the session which will use the guest account/character.
|
||||
|
||||
Returns:
|
||||
GUEST_ENABLED (boolean), player (Player):
|
||||
GUEST_ENABLED (boolean), account (Account):
|
||||
the boolean is whether guest accounts are enabled at all.
|
||||
the Player which was created from an available guest name.
|
||||
the Account which was created from an available guest name.
|
||||
"""
|
||||
# check if guests are enabled.
|
||||
if not settings.GUEST_ENABLED:
|
||||
|
|
@ -105,25 +105,25 @@ def create_guest_player(session):
|
|||
|
||||
try:
|
||||
# Find an available guest name.
|
||||
playername = None
|
||||
accountname = None
|
||||
for name in settings.GUEST_LIST:
|
||||
if not PlayerDB.objects.filter(username__iexact=playername).count():
|
||||
playername = name
|
||||
if not AccountDB.objects.filter(username__iexact=accountname).count():
|
||||
accountname = name
|
||||
break
|
||||
if not playername:
|
||||
if not accountname:
|
||||
session.msg("All guest accounts are in use. Please try again later.")
|
||||
return True, None
|
||||
else:
|
||||
# build a new player with the found guest playername
|
||||
# build a new account with the found guest accountname
|
||||
password = "%016x" % getrandbits(64)
|
||||
home = ObjectDB.objects.get_id(settings.GUEST_HOME)
|
||||
permissions = settings.PERMISSION_GUEST_DEFAULT
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
ptypeclass = settings.BASE_GUEST_TYPECLASS
|
||||
new_player = _create_player(session, playername, password, permissions, ptypeclass)
|
||||
if new_player:
|
||||
_create_character(session, new_player, typeclass, home, permissions)
|
||||
return True, new_player
|
||||
new_account = _create_account(session, accountname, password, permissions, ptypeclass)
|
||||
if new_account:
|
||||
_create_character(session, new_account, typeclass, home, permissions)
|
||||
return True, new_account
|
||||
|
||||
except Exception:
|
||||
# We are in the middle between logged in and -not, so we have
|
||||
|
|
@ -134,17 +134,17 @@ def create_guest_player(session):
|
|||
raise
|
||||
|
||||
|
||||
def create_normal_player(session, name, password):
|
||||
def create_normal_account(session, name, password):
|
||||
"""
|
||||
Creates a player with the given name and password.
|
||||
Creates an account with the given name and password.
|
||||
|
||||
Args:
|
||||
session (Session): the session which is requesting to create a player.
|
||||
name (str): the name that the player wants to use for login.
|
||||
password (str): the password desired by this player, for login.
|
||||
session (Session): the session which is requesting to create an account.
|
||||
name (str): the name that the account wants to use for login.
|
||||
password (str): the password desired by this account, for login.
|
||||
|
||||
Returns:
|
||||
player (Player): the player which was created from the name and password.
|
||||
account (Account): the account which was created from the name and password.
|
||||
"""
|
||||
# check for too many login errors too quick.
|
||||
if _throttle(session, maxlim=5, timeout=5*60):
|
||||
|
|
@ -153,22 +153,22 @@ def create_normal_player(session, name, password):
|
|||
return None
|
||||
|
||||
# Match account name and check password
|
||||
player = authenticate(username=name, password=password)
|
||||
account = authenticate(username=name, password=password)
|
||||
|
||||
if not player:
|
||||
# No playername or password match
|
||||
if not account:
|
||||
# No accountname or password match
|
||||
session.msg("Incorrect login information given.")
|
||||
# this just updates the throttle
|
||||
_throttle(session)
|
||||
# calls player hook for a failed login if possible.
|
||||
player = PlayerDB.objects.get_player_from_name(name)
|
||||
if player:
|
||||
player.at_failed_login(session)
|
||||
# calls account hook for a failed login if possible.
|
||||
account = AccountDB.objects.get_account_from_name(name)
|
||||
if account:
|
||||
account.at_failed_login(session)
|
||||
return None
|
||||
|
||||
# Check IP and/or name bans
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
if bans and (any(tup[0] == player.name.lower() for tup in bans)
|
||||
if bans and (any(tup[0] == account.name.lower() for tup in bans)
|
||||
or
|
||||
any(tup[2].match(session.address) for tup in bans if tup[2])):
|
||||
# this is a banned IP or name!
|
||||
|
|
@ -178,7 +178,7 @@ def create_normal_player(session, name, password):
|
|||
session.sessionhandler.disconnect(session, "Good bye! Disconnecting.")
|
||||
return None
|
||||
|
||||
return player
|
||||
return account
|
||||
|
||||
|
||||
class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -186,8 +186,8 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
|
|||
connect to the game
|
||||
|
||||
Usage (at login screen):
|
||||
connect playername password
|
||||
connect "player name" "pass word"
|
||||
connect accountname password
|
||||
connect "account name" "pass word"
|
||||
|
||||
Use the create command to first create an account before logging in.
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
|
|||
have a unique position in that their func() receives
|
||||
a session object instead of a source_object like all
|
||||
other types of logged-in commands (this is because
|
||||
there is no object yet before the player has logged in)
|
||||
there is no object yet before the account has logged in)
|
||||
"""
|
||||
session = self.caller
|
||||
|
||||
|
|
@ -222,9 +222,9 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
|
|||
parts = parts[0].split(None, 1)
|
||||
# Guest login
|
||||
if len(parts) == 1 and parts[0].lower() == "guest":
|
||||
enabled, new_player = create_guest_player(session)
|
||||
if new_player:
|
||||
session.sessionhandler.login(session, new_player)
|
||||
enabled, new_account = create_guest_account(session)
|
||||
if new_account:
|
||||
session.sessionhandler.login(session, new_account)
|
||||
if enabled:
|
||||
return
|
||||
|
||||
|
|
@ -233,20 +233,20 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
name, password = parts
|
||||
player = create_normal_player(session, name, password)
|
||||
if player:
|
||||
session.sessionhandler.login(session, player)
|
||||
account = create_normal_account(session, name, password)
|
||||
if account:
|
||||
session.sessionhandler.login(session, account)
|
||||
|
||||
|
||||
class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
create a new player account
|
||||
create a new account account
|
||||
|
||||
Usage (at login screen):
|
||||
create <playername> <password>
|
||||
create "player name" "pass word"
|
||||
create <accountname> <password>
|
||||
create "account name" "pass word"
|
||||
|
||||
This creates a new player account.
|
||||
This creates a new account account.
|
||||
|
||||
If you have spaces in your name, enclose it in double quotes.
|
||||
"""
|
||||
|
|
@ -271,25 +271,25 @@ class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
|
|||
"\nIf <name> or <password> contains spaces, enclose it in double quotes."
|
||||
session.msg(string)
|
||||
return
|
||||
playername, password = parts
|
||||
accountname, password = parts
|
||||
|
||||
# sanity checks
|
||||
if not re.findall(r"^[\w. @+\-']+$", playername) or not (0 < len(playername) <= 30):
|
||||
if not re.findall(r"^[\w. @+\-']+$", accountname) or not (0 < len(accountname) <= 30):
|
||||
# this echoes the restrictions made by django's auth
|
||||
# module (except not allowing spaces, for convenience of
|
||||
# logging in).
|
||||
string = "\n\r Playername can max be 30 characters or fewer. Letters, spaces, digits and @/./+/-/_/' only."
|
||||
string = "\n\r Accountname can max be 30 characters or fewer. Letters, spaces, digits and @/./+/-/_/' only."
|
||||
session.msg(string)
|
||||
return
|
||||
# strip excessive spaces in playername
|
||||
playername = re.sub(r"\s+", " ", playername).strip()
|
||||
if PlayerDB.objects.filter(username__iexact=playername):
|
||||
# player already exists (we also ignore capitalization here)
|
||||
session.msg("Sorry, there is already a player with the name '%s'." % playername)
|
||||
# strip excessive spaces in accountname
|
||||
accountname = re.sub(r"\s+", " ", accountname).strip()
|
||||
if AccountDB.objects.filter(username__iexact=accountname):
|
||||
# account already exists (we also ignore capitalization here)
|
||||
session.msg("Sorry, there is already an account with the name '%s'." % accountname)
|
||||
return
|
||||
# Reserve playernames found in GUEST_LIST
|
||||
if settings.GUEST_LIST and playername.lower() in (guest.lower() for guest in settings.GUEST_LIST):
|
||||
string = "\n\r That name is reserved. Please choose another Playername."
|
||||
# Reserve accountnames found in GUEST_LIST
|
||||
if settings.GUEST_LIST and accountname.lower() in (guest.lower() for guest in settings.GUEST_LIST):
|
||||
string = "\n\r That name is reserved. Please choose another Accountname."
|
||||
session.msg(string)
|
||||
return
|
||||
if not re.findall(r"^[\w. @+\-']+$", password) or not (3 < len(password)):
|
||||
|
|
@ -301,7 +301,7 @@ class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
# Check IP and/or name bans
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
if bans and (any(tup[0] == playername.lower() for tup in bans)
|
||||
if bans and (any(tup[0] == accountname.lower() for tup in bans)
|
||||
or
|
||||
any(tup[2].match(session.address) for tup in bans if tup[2])):
|
||||
# this is a banned IP or name!
|
||||
|
|
@ -311,22 +311,22 @@ class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
|
|||
session.sessionhandler.disconnect(session, "Good bye! Disconnecting.")
|
||||
return
|
||||
|
||||
# everything's ok. Create the new player account.
|
||||
# everything's ok. Create the new account account.
|
||||
try:
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
new_player = _create_player(session, playername, password, permissions)
|
||||
if new_player:
|
||||
new_account = _create_account(session, accountname, password, permissions)
|
||||
if new_account:
|
||||
if MULTISESSION_MODE < 2:
|
||||
default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
|
||||
_create_character(session, new_player, typeclass, default_home, permissions)
|
||||
_create_character(session, new_account, typeclass, default_home, permissions)
|
||||
# tell the caller everything went well.
|
||||
string = "A new account '%s' was created. Welcome!"
|
||||
if " " in playername:
|
||||
if " " in accountname:
|
||||
string += "\n\nYou can now log in with the command 'connect \"%s\" <your password>'."
|
||||
else:
|
||||
string += "\n\nYou can now log with the command 'connect %s <your password>'."
|
||||
session.msg(string % (playername, playername))
|
||||
session.msg(string % (accountname, accountname))
|
||||
|
||||
except Exception:
|
||||
# We are in the middle between logged in and -not, so we have
|
||||
|
|
@ -344,7 +344,7 @@ class CmdUnconnectedQuit(COMMAND_DEFAULT_CLASS):
|
|||
quit
|
||||
|
||||
We maintain a different version of the quit command
|
||||
here for unconnected players for the sake of simplicity. The logged in
|
||||
here for unconnected accounts for the sake of simplicity. The logged in
|
||||
version is a bit more complicated.
|
||||
"""
|
||||
key = "quit"
|
||||
|
|
@ -516,50 +516,50 @@ class CmdUnconnectedScreenreader(COMMAND_DEFAULT_CLASS):
|
|||
self.session.sessionhandler.session_portal_sync(self.session)
|
||||
|
||||
|
||||
def _create_player(session, playername, password, permissions, typeclass=None, email=None):
|
||||
def _create_account(session, accountname, password, permissions, typeclass=None, email=None):
|
||||
"""
|
||||
Helper function, creates a player of the specified typeclass.
|
||||
Helper function, creates an account of the specified typeclass.
|
||||
"""
|
||||
try:
|
||||
new_player = create.create_player(playername, email, password, permissions=permissions, typeclass=typeclass)
|
||||
new_account = create.create_account(accountname, email, password, permissions=permissions, typeclass=typeclass)
|
||||
|
||||
except Exception as e:
|
||||
session.msg("There was an error creating the Player:\n%s\n If this problem persists, contact an admin." % e)
|
||||
session.msg("There was an error creating the Account:\n%s\n If this problem persists, contact an admin." % e)
|
||||
logger.log_trace()
|
||||
return False
|
||||
|
||||
# This needs to be set so the engine knows this player is
|
||||
# This needs to be set so the engine knows this account is
|
||||
# logging in for the first time. (so it knows to call the right
|
||||
# hooks during login later)
|
||||
new_player.db.FIRST_LOGIN = True
|
||||
new_account.db.FIRST_LOGIN = True
|
||||
|
||||
# join the new player to the public channel
|
||||
# join the new account to the public channel
|
||||
pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"])
|
||||
if not pchannel or not pchannel.connect(new_player):
|
||||
string = "New player '%s' could not connect to public channel!" % new_player.key
|
||||
if not pchannel or not pchannel.connect(new_account):
|
||||
string = "New account '%s' could not connect to public channel!" % new_account.key
|
||||
logger.log_err(string)
|
||||
return new_player
|
||||
return new_account
|
||||
|
||||
|
||||
def _create_character(session, new_player, typeclass, home, permissions):
|
||||
def _create_character(session, new_account, typeclass, home, permissions):
|
||||
"""
|
||||
Helper function, creates a character based on a player's name.
|
||||
Helper function, creates a character based on an account's name.
|
||||
This is meant for Guest and MULTISESSION_MODE < 2 situations.
|
||||
"""
|
||||
try:
|
||||
new_character = create.create_object(typeclass, key=new_player.key, home=home, permissions=permissions)
|
||||
new_character = create.create_object(typeclass, key=new_account.key, home=home, permissions=permissions)
|
||||
# set playable character list
|
||||
new_player.db._playable_characters.append(new_character)
|
||||
new_account.db._playable_characters.append(new_character)
|
||||
|
||||
# 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))
|
||||
# allow only the character itself and the account to puppet this character (and Developers).
|
||||
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)" %
|
||||
(new_character.id, new_account.id))
|
||||
|
||||
# If no description is set, set a default description
|
||||
if not new_character.db.desc:
|
||||
new_character.db.desc = "This is a Player."
|
||||
new_character.db.desc = "This is an Account."
|
||||
# We need to set this to have @ic auto-connect to this character
|
||||
new_player.db._last_puppet = new_character
|
||||
new_account.db._last_puppet = new_character
|
||||
except Exception as e:
|
||||
session.msg("There was an error creating the Character:\n%s\n If this problem persists, contact an admin." % e)
|
||||
logger.log_trace()
|
||||
|
|
|
|||
|
|
@ -266,15 +266,15 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
|
|||
deferred.addCallback(_callback)
|
||||
return deferred
|
||||
|
||||
def test_from_player(self):
|
||||
from evennia.commands.default.cmdset_player import PlayerCmdSet
|
||||
def test_from_account(self):
|
||||
from evennia.commands.default.cmdset_account import AccountCmdSet
|
||||
a = self.cmdset_a
|
||||
a.no_channels = True
|
||||
self.set_cmdsets(self.player, a)
|
||||
deferred = cmdhandler.get_and_merge_cmdsets(self.player, None, self.player, None, "player", "")
|
||||
self.set_cmdsets(self.account, a)
|
||||
deferred = cmdhandler.get_and_merge_cmdsets(self.account, None, self.account, None, "account", "")
|
||||
# get_and_merge_cmdsets converts to lower-case internally.
|
||||
def _callback(cmdset):
|
||||
pcmdset = PlayerCmdSet()
|
||||
pcmdset = AccountCmdSet()
|
||||
pcmdset.at_cmdset_creation()
|
||||
pcmds = [cmd.key for cmd in pcmdset.commands] + ["a", "b", "c", "d"]
|
||||
self.assertTrue(all(cmd.key in pcmds for cmd in cmdset.commands))
|
||||
|
|
@ -305,18 +305,18 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
|
|||
|
||||
def test_autocmdsets(self):
|
||||
import evennia
|
||||
from evennia.commands.default.cmdset_player import PlayerCmdSet
|
||||
from evennia.commands.default.cmdset_account import AccountCmdSet
|
||||
from evennia.comms.channelhandler import CHANNEL_HANDLER
|
||||
testchannel = evennia.create_channel("channeltest", locks="listen:all();send:all()")
|
||||
CHANNEL_HANDLER.add(testchannel)
|
||||
CHANNEL_HANDLER.update()
|
||||
self.assertTrue(testchannel.connect(self.player))
|
||||
self.assertTrue(testchannel.has_connection(self.player))
|
||||
self.assertTrue(testchannel.connect(self.account))
|
||||
self.assertTrue(testchannel.has_connection(self.account))
|
||||
a, b, c, d = self.cmdset_a, self.cmdset_b, self.cmdset_c, self.cmdset_d
|
||||
self.set_cmdsets(self.player, a, b, c, d)
|
||||
deferred = cmdhandler.get_and_merge_cmdsets(self.session, self.session, self.player, self.char1, "session", "")
|
||||
self.set_cmdsets(self.account, a, b, c, d)
|
||||
deferred = cmdhandler.get_and_merge_cmdsets(self.session, self.session, self.account, self.char1, "session", "")
|
||||
def _callback(cmdset):
|
||||
pcmdset = PlayerCmdSet()
|
||||
pcmdset = AccountCmdSet()
|
||||
pcmdset.at_cmdset_creation()
|
||||
pcmds = [cmd.key for cmd in pcmdset.commands] + ["a", "b", "c", "d"] + ["out"]
|
||||
self.assertTrue(all(cmd.key or hasattr(cmd, "is_channel") in pcmds for cmd in cmdset.commands))
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class ChannelCommand(command.Command):
|
|||
self.msg(string % channelkey)
|
||||
return
|
||||
if msg == "on":
|
||||
caller = caller if not hasattr(caller, 'player') else caller.player
|
||||
caller = caller if not hasattr(caller, 'account') else caller.account
|
||||
unmuted = channel.unmute(caller)
|
||||
if unmuted:
|
||||
self.msg("You start listening to %s." % channel)
|
||||
|
|
@ -120,7 +120,7 @@ class ChannelCommand(command.Command):
|
|||
self.msg("You were already listening to %s." % channel)
|
||||
return
|
||||
if msg == "off":
|
||||
caller = caller if not hasattr(caller, 'player') else caller.player
|
||||
caller = caller if not hasattr(caller, 'account') else caller.account
|
||||
muted = channel.mute(caller)
|
||||
if muted:
|
||||
self.msg("You stop listening to %s." % channel)
|
||||
|
|
@ -134,7 +134,7 @@ class ChannelCommand(command.Command):
|
|||
if "[-]" in line else line for line in lines))
|
||||
tail_log_file(log_file, self.history_start, 20, callback=send_msg)
|
||||
else:
|
||||
caller = caller if not hasattr(caller, 'player') else caller.player
|
||||
caller = caller if not hasattr(caller, 'account') else caller.account
|
||||
if caller in channel.mutelist:
|
||||
self.msg("You currently have %s muted." % channel)
|
||||
return
|
||||
|
|
@ -145,7 +145,7 @@ class ChannelCommand(command.Command):
|
|||
Let users know that this command is for communicating on a channel.
|
||||
|
||||
Args:
|
||||
caller (TypedObject): A Character or Player who has entered an ambiguous command.
|
||||
caller (TypedObject): A Character or Account who has entered an ambiguous command.
|
||||
|
||||
Returns:
|
||||
A string with identifying information to disambiguate the object, conventionally with a preceding space.
|
||||
|
|
|
|||
|
|
@ -62,26 +62,26 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
|
||||
def has_connection(self, subscriber):
|
||||
"""
|
||||
Checks so this player is actually listening
|
||||
Checks so this account is actually listening
|
||||
to this channel.
|
||||
|
||||
Args:
|
||||
subscriber (Player or Object): Entity to check.
|
||||
subscriber (Account or Object): Entity to check.
|
||||
|
||||
Returns:
|
||||
has_sub (bool): Whether the subscriber is subscribing to
|
||||
this channel or not.
|
||||
|
||||
Notes:
|
||||
This will first try Player subscribers and only try Object
|
||||
if the Player fails.
|
||||
This will first try Account subscribers and only try Object
|
||||
if the Account fails.
|
||||
|
||||
"""
|
||||
has_sub = self.subscriptions.has(subscriber)
|
||||
if not has_sub and hasattr(subscriber, "player"):
|
||||
if not has_sub and hasattr(subscriber, "account"):
|
||||
# it's common to send an Object when we
|
||||
# by default only allow Players to subscribe.
|
||||
has_sub = self.subscriptions.has(subscriber.player)
|
||||
# by default only allow Accounts to subscribe.
|
||||
has_sub = self.subscriptions.has(subscriber.account)
|
||||
return has_sub
|
||||
|
||||
@property
|
||||
|
|
@ -94,16 +94,22 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
listening = [ob for ob in subs if ob.is_connected and ob not in self.mutelist]
|
||||
if subs:
|
||||
# display listening subscribers in bold
|
||||
string = ", ".join([player.key if player not in listening else "|w%s|n" % player.key for player in subs])
|
||||
string = ", ".join([account.key if account not in listening else "|w%s|n" % account.key for account in subs])
|
||||
else:
|
||||
string = "<None>"
|
||||
return string
|
||||
|
||||
def mute(self, subscriber):
|
||||
def mute(self, subscriber, **kwargs):
|
||||
"""
|
||||
Adds an entity to the list of muted subscribers.
|
||||
A muted subscriber will no longer see channel messages,
|
||||
but may use channel commands.
|
||||
|
||||
Args:
|
||||
subscriber (Object or Account): Subscriber to mute.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
mutelist = self.mutelist
|
||||
if subscriber not in mutelist:
|
||||
|
|
@ -112,11 +118,16 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
return True
|
||||
return False
|
||||
|
||||
def unmute(self, subscriber):
|
||||
def unmute(self, subscriber, **kwargs):
|
||||
"""
|
||||
Removes an entity to the list of muted subscribers.
|
||||
A muted subscriber will no longer see channel messages,
|
||||
Removes an entity to the list of muted subscribers. A muted subscriber will no longer see channel messages,
|
||||
but may use channel commands.
|
||||
|
||||
Args:
|
||||
subscriber (Object or Account): The subscriber to unmute.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
mutelist = self.mutelist
|
||||
if subscriber in mutelist:
|
||||
|
|
@ -125,13 +136,15 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
return True
|
||||
return False
|
||||
|
||||
def connect(self, subscriber):
|
||||
def connect(self, subscriber, **kwargs):
|
||||
"""
|
||||
Connect the user to this channel. This checks access.
|
||||
|
||||
Args:
|
||||
subscriber (Player or Object): the entity to subscribe
|
||||
subscriber (Account or Object): the entity to subscribe
|
||||
to this channel.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
success (bool): Whether or not the addition was
|
||||
|
|
@ -153,13 +166,15 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
self.post_join_channel(subscriber)
|
||||
return True
|
||||
|
||||
def disconnect(self, subscriber):
|
||||
def disconnect(self, subscriber, **kwargs):
|
||||
"""
|
||||
Disconnect entity from this channel.
|
||||
|
||||
Args:
|
||||
subscriber (Player of Object): the
|
||||
subscriber (Account of Object): the
|
||||
entity to disconnect.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
success (bool): Whether or not the removal was
|
||||
|
|
@ -178,7 +193,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
self.post_leave_channel(subscriber)
|
||||
return True
|
||||
|
||||
def access(self, accessing_obj, access_type='listen', default=False, no_superuser_bypass=False):
|
||||
def access(self, accessing_obj, access_type='listen', default=False, no_superuser_bypass=False, **kwargs):
|
||||
"""
|
||||
Determines if another object has permission to access.
|
||||
|
||||
|
|
@ -188,6 +203,8 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
default (bool, optional): What to return if no lock of access_type was found
|
||||
no_superuser_bypass (bool, optional): Turns off superuser
|
||||
lock bypass. Be careful with this one.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
return (bool): Result of lock check.
|
||||
|
|
@ -208,7 +225,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
CHANNELHANDLER.update()
|
||||
|
||||
def message_transform(self, msgobj, emit=False, prefix=True,
|
||||
sender_strings=None, external=False):
|
||||
sender_strings=None, external=False, **kwargs):
|
||||
"""
|
||||
Generates the formatted string sent to listeners on a channel.
|
||||
|
||||
|
|
@ -219,6 +236,8 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
prefix (bool, optional): Prefix `msg` with a text given by `self.channel_prefix`.
|
||||
sender_strings (list, optional): Used by bots etc, one string per external sender.
|
||||
external (bool, optional): If this is an external sender or not.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
if sender_strings or external:
|
||||
|
|
@ -230,7 +249,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
msgobj.message = body
|
||||
return msgobj
|
||||
|
||||
def distribute_message(self, msgobj, online=False):
|
||||
def distribute_message(self, msgobj, online=False, **kwargs):
|
||||
"""
|
||||
Method for grabbing all listeners that a message should be
|
||||
sent to on this channel, and sending them a message.
|
||||
|
|
@ -238,12 +257,15 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
Args:
|
||||
msgobj (Msg or TempMsg): Message to distribute.
|
||||
online (bool): Only send to receivers who are actually online
|
||||
(not currently used):
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
This is also where logging happens, if enabled.
|
||||
|
||||
"""
|
||||
# get all players or objects connected to this channel and send to them
|
||||
# get all accounts or objects connected to this channel and send to them
|
||||
if online:
|
||||
subs = self.subscriptions.online()
|
||||
else:
|
||||
|
|
@ -254,7 +276,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
continue
|
||||
try:
|
||||
# note our addition of the from_channel keyword here. This could be checked
|
||||
# by a custom player.msg() to treat channel-receives differently.
|
||||
# by a custom account.msg() to treat channel-receives differently.
|
||||
entity.msg(msgobj.message, from_obj=msgobj.senders, options={"from_channel": self.id})
|
||||
except AttributeError as e:
|
||||
logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity))
|
||||
|
|
@ -266,7 +288,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
def msg(self, msgobj, header=None, senders=None, sender_strings=None,
|
||||
keep_log=None, online=False, emit=False, external=False):
|
||||
"""
|
||||
Send the given message to all players connected to channel. Note that
|
||||
Send the given message to all accounts connected to channel. Note that
|
||||
no permission-checking is done here; it is assumed to have been
|
||||
done before calling this method. The optional keywords are not used if
|
||||
persistent is False.
|
||||
|
|
@ -278,10 +300,10 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
(if persistent=False) or it will be used together with `header`
|
||||
and `senders` keywords to create a Msg instance on the fly.
|
||||
header (str, optional): A header for building the message.
|
||||
senders (Object, Player or list, optional): Optional if persistent=False, used
|
||||
senders (Object, Account or list, optional): Optional if persistent=False, used
|
||||
to build senders for the message.
|
||||
sender_strings (list, optional): Name strings of senders. Used for external
|
||||
connections where the sender is not a player or object.
|
||||
connections where the sender is not an account or object.
|
||||
When this is defined, external will be assumed.
|
||||
keep_log (bool or None, optional): This allows to temporarily change the logging status of
|
||||
this channel message. If `None`, the Channel's `keep_log` Attribute will
|
||||
|
|
@ -289,8 +311,8 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
message only (note that for unlogged channels, a `True` value here will
|
||||
create a new log file only for this message).
|
||||
online (bool, optional) - If this is set true, only messages people who are
|
||||
online. Otherwise, messages all players connected. This can
|
||||
make things faster, but may not trigger listeners on players
|
||||
online. Otherwise, messages all accounts connected. This can
|
||||
make things faster, but may not trigger listeners on accounts
|
||||
that are offline.
|
||||
emit (bool, optional) - Signals to the message formatter that this message is
|
||||
not to be directly associated with a name.
|
||||
|
|
@ -334,7 +356,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
|
||||
# hooks
|
||||
|
||||
def channel_prefix(self, msg=None, emit=False):
|
||||
def channel_prefix(self, msg=None, emit=False, **kwargs):
|
||||
|
||||
"""
|
||||
Hook method. How the channel should prefix itself for users.
|
||||
|
|
@ -343,6 +365,8 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
msg (str, optional): Prefix text
|
||||
emit (bool, optional): Switches to emit mode, which usually
|
||||
means to not prefix the channel's info.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
prefix (str): The created channel prefix.
|
||||
|
|
@ -350,12 +374,14 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
"""
|
||||
return '' if emit else '[%s] ' % self.key
|
||||
|
||||
def format_senders(self, senders=None):
|
||||
def format_senders(self, senders=None, **kwargs):
|
||||
"""
|
||||
Hook method. Function used to format a list of sender names.
|
||||
|
||||
Args:
|
||||
senders (list): Sender object names.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
formatted_list (str): The list of names formatted appropriately.
|
||||
|
|
@ -363,14 +389,14 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
Notes:
|
||||
This function exists separately so that external sources
|
||||
can use it to format source names in the same manner as
|
||||
normal object/player names.
|
||||
normal object/account names.
|
||||
|
||||
"""
|
||||
if not senders:
|
||||
return ''
|
||||
return ', '.join(senders)
|
||||
|
||||
def pose_transform(self, msgobj, sender_string):
|
||||
def pose_transform(self, msgobj, sender_string, **kwargs):
|
||||
"""
|
||||
Hook method. Detects if the sender is posing, and modifies the
|
||||
message accordingly.
|
||||
|
|
@ -378,6 +404,8 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
Args:
|
||||
msgobj (Msg or TempMsg): The message to analyze for a pose.
|
||||
sender_string (str): The name of the sender/poser.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
string (str): A message that combines the `sender_string`
|
||||
|
|
@ -400,17 +428,19 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
else:
|
||||
return '%s: %s' % (sender_string, message)
|
||||
|
||||
def format_external(self, msgobj, senders, emit=False):
|
||||
def format_external(self, msgobj, senders, emit=False, **kwargs):
|
||||
"""
|
||||
Hook method. Used for formatting external messages. This is
|
||||
needed as a separate operation because the senders of external
|
||||
messages may not be in-game objects/players, and so cannot
|
||||
messages may not be in-game objects/accounts, and so cannot
|
||||
have things like custom user preferences.
|
||||
|
||||
Args:
|
||||
msgobj (Msg or TempMsg): The message to send.
|
||||
senders (list): Strings, one per sender.
|
||||
emit (bool, optional): A sender-agnostic message or not.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
transformed (str): A formatted string.
|
||||
|
|
@ -421,13 +451,15 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
senders = ', '.join(senders)
|
||||
return self.pose_transform(msgobj, senders)
|
||||
|
||||
def format_message(self, msgobj, emit=False):
|
||||
def format_message(self, msgobj, emit=False, **kwargs):
|
||||
"""
|
||||
Hook method. Formats a message body for display.
|
||||
|
||||
Args:
|
||||
msgobj (Msg or TempMsg): The message object to send.
|
||||
emit (bool, optional): The message is agnostic of senders.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
transformed (str): The formatted message.
|
||||
|
|
@ -445,13 +477,15 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
senders = ', '.join(senders)
|
||||
return self.pose_transform(msgobj, senders)
|
||||
|
||||
def pre_join_channel(self, joiner):
|
||||
def pre_join_channel(self, joiner, **kwargs):
|
||||
"""
|
||||
Hook method. Runs right before a channel is joined. If this
|
||||
returns a false value, channel joining is aborted.
|
||||
|
||||
Args:
|
||||
joiner (object): The joining object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
should_join (bool): If `False`, channel joining is aborted.
|
||||
|
|
@ -459,23 +493,27 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
"""
|
||||
return True
|
||||
|
||||
def post_join_channel(self, joiner):
|
||||
def post_join_channel(self, joiner, **kwargs):
|
||||
"""
|
||||
Hook method. Runs right after an object or player joins a channel.
|
||||
Hook method. Runs right after an object or account joins a channel.
|
||||
|
||||
Args:
|
||||
joiner (object): The joining object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def pre_leave_channel(self, leaver):
|
||||
def pre_leave_channel(self, leaver, **kwargs):
|
||||
"""
|
||||
Hook method. Runs right before a user leaves a channel. If this returns a false
|
||||
value, leaving the channel will be aborted.
|
||||
|
||||
Args:
|
||||
leaver (object): The leaving object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
should_leave (bool): If `False`, channel parting is aborted.
|
||||
|
|
@ -483,17 +521,19 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
"""
|
||||
return True
|
||||
|
||||
def post_leave_channel(self, leaver):
|
||||
def post_leave_channel(self, leaver, **kwargs):
|
||||
"""
|
||||
Hook method. Runs right after an object or player leaves a channel.
|
||||
Hook method. Runs right after an object or account leaves a channel.
|
||||
|
||||
Args:
|
||||
leaver (object): The leaving object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def pre_send_message(self, msg):
|
||||
def pre_send_message(self, msg, **kwargs):
|
||||
"""
|
||||
Hook method. Runs before a message is sent to the channel and
|
||||
should return the message object, after any transformations.
|
||||
|
|
@ -501,6 +541,8 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
|
||||
Args:
|
||||
msg (Msg or TempMsg): Message to send.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
result (Msg, TempMsg or bool): If False, abort send.
|
||||
|
|
@ -508,12 +550,14 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
|
|||
"""
|
||||
return msg
|
||||
|
||||
def post_send_message(self, msg):
|
||||
def post_send_message(self, msg, **kwargs):
|
||||
"""
|
||||
Hook method. Run after a message is sent to the channel.
|
||||
|
||||
Args:
|
||||
msg (Msg or TempMsg): Message sent.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@ Comm system components.
|
|||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from evennia.typeclasses.managers import (TypedObjectManager, TypeclassManager,
|
||||
returns_typeclass_list, returns_typeclass)
|
||||
from evennia.typeclasses.managers import (TypedObjectManager, TypeclassManager)
|
||||
from evennia.utils import logger
|
||||
|
||||
_GA = object.__getattribute__
|
||||
_PlayerDB = None
|
||||
_AccountDB = None
|
||||
_ObjectDB = None
|
||||
_ChannelDB = None
|
||||
_SESSIONS = None
|
||||
|
|
@ -59,7 +57,7 @@ def dbref(inp, reqhash=True):
|
|||
|
||||
def identify_object(inp):
|
||||
"""
|
||||
Helper function. Identifies if an object is a player or an object;
|
||||
Helper function. Identifies if an object is an account or an object;
|
||||
return its database model
|
||||
|
||||
Args:
|
||||
|
|
@ -67,14 +65,14 @@ def identify_object(inp):
|
|||
|
||||
Returns:
|
||||
identified (tuple): This is a tuple with (`inp`, identifier)
|
||||
where `identifier` is one of "player", "object", "channel",
|
||||
where `identifier` is one of "account", "object", "channel",
|
||||
"string", "dbref" or None.
|
||||
|
||||
"""
|
||||
if hasattr(inp, "__dbclass__"):
|
||||
clsname = inp.__dbclass__.__name__
|
||||
if clsname == "PlayerDB":
|
||||
return inp, "player"
|
||||
if clsname == "AccountDB":
|
||||
return inp, "account"
|
||||
elif clsname == "ObjectDB":
|
||||
return inp ,"object"
|
||||
elif clsname == "ChannelDB":
|
||||
|
|
@ -87,14 +85,14 @@ def identify_object(inp):
|
|||
return inp, None
|
||||
|
||||
|
||||
def to_object(inp, objtype='player'):
|
||||
def to_object(inp, objtype='account'):
|
||||
"""
|
||||
Locates the object related to the given playername or channel key.
|
||||
Locates the object related to the given accountname or channel key.
|
||||
If input was already the correct object, return it.
|
||||
|
||||
Args:
|
||||
inp (any): The input object/string
|
||||
objtype (str): Either 'player' or 'channel'.
|
||||
objtype (str): Either 'account' or 'channel'.
|
||||
|
||||
Returns:
|
||||
obj (object): The correct object related to `inp`.
|
||||
|
|
@ -103,17 +101,17 @@ def to_object(inp, objtype='player'):
|
|||
obj, typ = identify_object(inp)
|
||||
if typ == objtype:
|
||||
return obj
|
||||
if objtype == 'player':
|
||||
if objtype == 'account':
|
||||
if typ == 'object':
|
||||
return obj.player
|
||||
return obj.account
|
||||
if typ == 'string':
|
||||
return _PlayerDB.objects.get(user_username__iexact=obj)
|
||||
return _AccountDB.objects.get(user_username__iexact=obj)
|
||||
if typ == 'dbref':
|
||||
return _PlayerDB.objects.get(id=obj)
|
||||
return _AccountDB.objects.get(id=obj)
|
||||
logger.log_err("%s %s %s %s %s", objtype, inp, obj, typ, type(inp))
|
||||
raise CommError()
|
||||
elif objtype == 'object':
|
||||
if typ == 'player':
|
||||
if typ == 'account':
|
||||
return obj.obj
|
||||
if typ == 'string':
|
||||
return _ObjectDB.objects.get(db_key__iexact=obj)
|
||||
|
|
@ -131,6 +129,7 @@ def to_object(inp, objtype='player'):
|
|||
# an unknown
|
||||
return None
|
||||
|
||||
|
||||
#
|
||||
# Msg manager
|
||||
#
|
||||
|
|
@ -159,7 +158,7 @@ class MsgManager(TypedObjectManager):
|
|||
|
||||
Returns:
|
||||
identified (tuple): This is a tuple with (`inp`, identifier)
|
||||
where `identifier` is one of "player", "object", "channel",
|
||||
where `identifier` is one of "account", "object", "channel",
|
||||
"string", "dbref" or None.
|
||||
|
||||
"""
|
||||
|
|
@ -184,10 +183,10 @@ class MsgManager(TypedObjectManager):
|
|||
def get_messages_by_sender(self, sender, exclude_channel_messages=False):
|
||||
"""
|
||||
Get all messages sent by one entity - this could be either a
|
||||
player or an object
|
||||
account or an object
|
||||
|
||||
Args:
|
||||
sender (Player or Object): The sender of the message.
|
||||
sender (Account or Object): The sender of the message.
|
||||
exclude_channel_messages (bool, optional): Only return messages
|
||||
not aimed at a channel (that is, private tells for example)
|
||||
|
||||
|
|
@ -201,9 +200,9 @@ class MsgManager(TypedObjectManager):
|
|||
obj, typ = identify_object(sender)
|
||||
if exclude_channel_messages:
|
||||
# explicitly exclude channel recipients
|
||||
if typ == 'player':
|
||||
return list(self.filter(db_sender_players=obj,
|
||||
db_receivers_channels__isnull=True).exclude(db_hide_from_players=obj))
|
||||
if typ == 'account':
|
||||
return list(self.filter(db_sender_accounts=obj,
|
||||
db_receivers_channels__isnull=True).exclude(db_hide_from_accounts=obj))
|
||||
elif typ == 'object':
|
||||
return list(self.filter(db_sender_objects=obj,
|
||||
db_receivers_channels__isnull=True).exclude(db_hide_from_objects=obj))
|
||||
|
|
@ -211,8 +210,8 @@ class MsgManager(TypedObjectManager):
|
|||
raise CommError
|
||||
else:
|
||||
# get everything, channel or not
|
||||
if typ == 'player':
|
||||
return list(self.filter(db_sender_players=obj).exclude(db_hide_from_players=obj))
|
||||
if typ == 'account':
|
||||
return list(self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj))
|
||||
elif typ == 'object':
|
||||
return list(self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj))
|
||||
else:
|
||||
|
|
@ -223,7 +222,7 @@ class MsgManager(TypedObjectManager):
|
|||
Get all messages sent to one given recipient.
|
||||
|
||||
Args:
|
||||
recipient (Object, Player or Channel): The recipient of the messages to search for.
|
||||
recipient (Object, Account or Channel): The recipient of the messages to search for.
|
||||
|
||||
Returns:
|
||||
messages (list): Matching messages.
|
||||
|
|
@ -233,8 +232,8 @@ class MsgManager(TypedObjectManager):
|
|||
|
||||
"""
|
||||
obj, typ = identify_object(recipient)
|
||||
if typ == 'player':
|
||||
return list(self.filter(db_receivers_players=obj).exclude(db_hide_from_players=obj))
|
||||
if typ == 'account':
|
||||
return list(self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj))
|
||||
elif typ == 'object':
|
||||
return list(self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj))
|
||||
elif typ == 'channel':
|
||||
|
|
@ -261,9 +260,9 @@ class MsgManager(TypedObjectManager):
|
|||
one of the arguments must be given to do a search.
|
||||
|
||||
Args:
|
||||
sender (Object or Player, optional): Get messages sent by a particular player or object
|
||||
receiver (Object, Player or Channel, optional): Get messages
|
||||
received by a certain player,object or channel
|
||||
sender (Object or Account, optional): Get messages sent by a particular account or object
|
||||
receiver (Object, Account or Channel, optional): Get messages
|
||||
received by a certain account,object or channel
|
||||
freetext (str): Search for a text string in a message. NOTE:
|
||||
This can potentially be slow, so make sure to supply one of
|
||||
the other arguments to limit the search.
|
||||
|
|
@ -288,16 +287,16 @@ class MsgManager(TypedObjectManager):
|
|||
|
||||
# filter by sender
|
||||
sender, styp = identify_object(sender)
|
||||
if styp == 'player':
|
||||
sender_restrict = Q(db_sender_players=sender) & ~Q(db_hide_from_players=sender)
|
||||
if styp == 'account':
|
||||
sender_restrict = Q(db_sender_accounts=sender) & ~Q(db_hide_from_accounts=sender)
|
||||
elif styp == 'object':
|
||||
sender_restrict = Q(db_sender_objects=sender) & ~Q(db_hide_from_objects=sender)
|
||||
else:
|
||||
sender_restrict = Q()
|
||||
# filter by receiver
|
||||
receiver, rtyp = identify_object(receiver)
|
||||
if rtyp == 'player':
|
||||
receiver_restrict = Q(db_receivers_players=receiver) & ~Q(db_hide_from_players=receiver)
|
||||
if rtyp == 'account':
|
||||
receiver_restrict = Q(db_receivers_accounts=receiver) & ~Q(db_hide_from_accounts=receiver)
|
||||
elif rtyp == 'object':
|
||||
receiver_restrict = Q(db_receivers_objects=receiver) & ~Q(db_hide_from_objects=receiver)
|
||||
elif rtyp == 'channel':
|
||||
|
|
@ -314,6 +313,7 @@ class MsgManager(TypedObjectManager):
|
|||
# back-compatibility alias
|
||||
message_search = search_message
|
||||
|
||||
|
||||
#
|
||||
# Channel manager
|
||||
#
|
||||
|
|
@ -332,7 +332,6 @@ class ChannelDBManager(TypedObjectManager):
|
|||
subscribed to the Channel.
|
||||
|
||||
"""
|
||||
@returns_typeclass_list
|
||||
def get_all_channels(self):
|
||||
"""
|
||||
Get all channels.
|
||||
|
|
@ -343,7 +342,6 @@ class ChannelDBManager(TypedObjectManager):
|
|||
"""
|
||||
return self.all()
|
||||
|
||||
@returns_typeclass
|
||||
def get_channel(self, channelkey):
|
||||
"""
|
||||
Return the channel object if given its key.
|
||||
|
|
@ -366,26 +364,24 @@ class ChannelDBManager(TypedObjectManager):
|
|||
return channels[0]
|
||||
return None
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_subscriptions(self, subscriber):
|
||||
"""
|
||||
Return all channels a given entity is subscribed to.
|
||||
|
||||
Args:
|
||||
subscriber (Object or Player): The one subscribing.
|
||||
subscriber (Object or Account): The one subscribing.
|
||||
|
||||
Returns:
|
||||
subscriptions (list): Channel subscribed to.
|
||||
|
||||
"""
|
||||
clsname = subscriber.__dbclass__.__name__
|
||||
if clsname == "PlayerDB":
|
||||
return subscriber.subscription_set.all()
|
||||
if clsname == "AccountDB":
|
||||
return subscriber.account_subscription_set.all()
|
||||
if clsname == "ObjectDB":
|
||||
return subscriber.object_subscription_set.all()
|
||||
return []
|
||||
|
||||
@returns_typeclass_list
|
||||
def search_channel(self, ostring, exact=True):
|
||||
"""
|
||||
Search the channel database for a particular channel.
|
||||
|
|
@ -397,7 +393,8 @@ class ChannelDBManager(TypedObjectManager):
|
|||
|
||||
"""
|
||||
channels = []
|
||||
if not ostring: return channels
|
||||
if not ostring:
|
||||
return channels
|
||||
try:
|
||||
# try an id match first
|
||||
dbref = int(ostring.strip('#'))
|
||||
|
|
@ -414,16 +411,14 @@ class ChannelDBManager(TypedObjectManager):
|
|||
if not channels:
|
||||
# still no match. Search by alias.
|
||||
channels = [channel for channel in self.all()
|
||||
if ostring.lower() in [a.lower
|
||||
for a in channel.aliases.all()]]
|
||||
if ostring.lower() in [a.lower for a in channel.aliases.all()]]
|
||||
return channels
|
||||
# back-compatibility alias
|
||||
channel_search = search_channel
|
||||
|
||||
|
||||
class ChannelManager(ChannelDBManager, TypeclassManager):
|
||||
"""
|
||||
Wrapper to group the typeclass manager to a consistent name.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ class Migration(migrations.Migration):
|
|||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_hide_from_players',
|
||||
field=models.ManyToManyField(related_name=b'hide_from_players_set', null=True, to=settings.AUTH_USER_MODEL),
|
||||
name='db_hide_from_accounts',
|
||||
field=models.ManyToManyField(related_name=b'hide_from_accounts_set', null=True, to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
|
|
@ -35,8 +35,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_receivers_players',
|
||||
field=models.ManyToManyField(help_text=b'player receivers', related_name=b'receiver_player_set', null=True, to=settings.AUTH_USER_MODEL),
|
||||
name='db_receivers_accounts',
|
||||
field=models.ManyToManyField(help_text=b'account receivers', related_name=b'receiver_account_set', null=True, to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
|
|
@ -47,8 +47,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_sender_players',
|
||||
field=models.ManyToManyField(related_name=b'sender_player_set', null=True, verbose_name=b'sender(player)', to=settings.AUTH_USER_MODEL, db_index=True),
|
||||
name='db_sender_accounts',
|
||||
field=models.ManyToManyField(related_name=b'sender_account_set', null=True, verbose_name=b'sender(account)', to=settings.AUTH_USER_MODEL, db_index=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_hide_from_players',
|
||||
field=models.ManyToManyField(blank=True, null=True, related_name='hide_from_players_set', to=settings.AUTH_USER_MODEL),
|
||||
name='db_hide_from_accounts',
|
||||
field=models.ManyToManyField(blank=True, null=True, related_name='hide_from_accounts_set', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
|
|
@ -40,8 +40,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_receivers_players',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'player receivers', null=True, related_name='receiver_player_set', to=settings.AUTH_USER_MODEL),
|
||||
name='db_receivers_accounts',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'account receivers', null=True, related_name='receiver_account_set', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
|
|
@ -55,8 +55,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_sender_players',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, null=True, related_name='sender_player_set', to=settings.AUTH_USER_MODEL, verbose_name=b'sender(player)'),
|
||||
name='db_sender_accounts',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, null=True, related_name='sender_account_set', to=settings.AUTH_USER_MODEL, verbose_name=b'sender(account)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
|
|
|
|||
26
evennia/comms/migrations/0011_auto_20170217_2039.py
Normal file
26
evennia/comms/migrations/0011_auto_20170217_2039.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.11 on 2017-02-17 20:39
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0007_auto_20150403_2339'),
|
||||
('comms', '0010_auto_20161206_1912'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_receivers_scripts',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'script_receivers', null=True, related_name='receiver_script_set', to='scripts.ScriptDB'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_sender_scripts',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, null=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'),
|
||||
),
|
||||
]
|
||||
81
evennia/comms/migrations/0011_auto_20170606_1731.py
Normal file
81
evennia/comms/migrations/0011_auto_20170606_1731.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-06 17:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comms', '0010_auto_20161206_1912'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='channeldb',
|
||||
name='db_attributes',
|
||||
field=models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='channeldb',
|
||||
name='db_object_subscriptions',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'subscriptions'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='channeldb',
|
||||
name='db_subscriptions',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='subscription_set', to=settings.AUTH_USER_MODEL, verbose_name=b'subscriptions'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='channeldb',
|
||||
name='db_tags',
|
||||
field=models.ManyToManyField(help_text=b'tags on this object. Tags are simple string markers to identify, group and alias objects.', to='typeclasses.Tag'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_hide_from_channels',
|
||||
field=models.ManyToManyField(blank=True, related_name='hide_from_channels_set', to='comms.ChannelDB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_hide_from_objects',
|
||||
field=models.ManyToManyField(blank=True, related_name='hide_from_objects_set', to='objects.ObjectDB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_hide_from_accounts',
|
||||
field=models.ManyToManyField(blank=True, related_name='hide_from_accounts_set', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_receivers_channels',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'channel recievers', related_name='channel_set', to='comms.ChannelDB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_receivers_objects',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'object receivers', related_name='receiver_object_set', to='objects.ObjectDB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_receivers_accounts',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'account receivers', related_name='receiver_account_set', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_sender_objects',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_object_set', to='objects.ObjectDB', verbose_name=b'sender(object)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_sender_accounts',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_account_set', to=settings.AUTH_USER_MODEL, verbose_name=b'sender(account)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_tags',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'tags on this message. Tags are simple string markers to identify, group and alias messages.', to='typeclasses.Tag'),
|
||||
),
|
||||
]
|
||||
16
evennia/comms/migrations/0012_merge_20170617_2017.py
Normal file
16
evennia/comms/migrations/0012_merge_20170617_2017.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-17 20:17
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comms', '0011_auto_20170606_1731'),
|
||||
('comms', '0011_auto_20170217_2039'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
90
evennia/comms/migrations/0013_auto_20170705_1726.py
Normal file
90
evennia/comms/migrations/0013_auto_20170705_1726.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-05 17:26
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models, connection
|
||||
from django.db import OperationalError
|
||||
|
||||
|
||||
def _table_exists(db_cursor, tablename):
|
||||
"Returns bool if table exists or not"
|
||||
sql_check_exists = "SELECT * from %s;" % tablename
|
||||
try:
|
||||
db_cursor.execute(sql_check_exists)
|
||||
return True
|
||||
except OperationalError:
|
||||
return False
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0007_copy_player_to_account'),
|
||||
('comms', '0012_merge_20170617_2017'),
|
||||
]
|
||||
|
||||
db_cursor = connection.cursor()
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='channeldb',
|
||||
name='db_account_subscriptions',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='account_subscription_set', to='accounts.AccountDB', verbose_name=b'account subscriptions'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='channeldb',
|
||||
name='db_object_subscriptions',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'object subscriptions'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_receivers_scripts',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'script_receivers', related_name='receiver_script_set', to='scripts.ScriptDB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_sender_scripts',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='channeldb',
|
||||
name='db_object_subscriptions',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'object subscriptions'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_receivers_scripts',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'script_receivers', related_name='receiver_script_set', to='scripts.ScriptDB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='msg',
|
||||
name='db_sender_scripts',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'),
|
||||
),
|
||||
]
|
||||
|
||||
if _table_exists(db_cursor, 'comms_msg_db_hide_from_players'):
|
||||
# OBS - this is run BEFORE migrations are run!
|
||||
# not a migration of an existing database
|
||||
operations += [
|
||||
migrations.AddField(
|
||||
model_name='channeldb',
|
||||
name='db_account_subscriptions',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='account_subscription_set', to='accounts.AccountDB', verbose_name=b'account subscriptions'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_hide_from_accounts',
|
||||
field=models.ManyToManyField(blank=True, related_name='hide_from_accounts_set', to='accounts.AccountDB'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_receivers_accounts',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'account receivers', related_name='receiver_account_set', to='accounts.AccountDB'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='msg',
|
||||
name='db_sender_accounts',
|
||||
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_account_set', to='accounts.AccountDB', verbose_name=b'sender(account)'),
|
||||
),
|
||||
]
|
||||
43
evennia/comms/migrations/0014_auto_20170705_1736.py
Normal file
43
evennia/comms/migrations/0014_auto_20170705_1736.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-05 17:36
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
|
||||
try:
|
||||
apps.get_model('accounts', 'AccountDB')
|
||||
except LookupError:
|
||||
return
|
||||
AccountDB = apps.get_model('accounts', 'AccountDB')
|
||||
|
||||
Msg = apps.get_model('comms', 'Msg')
|
||||
for msg in Msg.objects.all():
|
||||
for account in msg.db_sender_accounts.all():
|
||||
account = AccountDB.objects.get(id=account.id)
|
||||
msg.db_sender_accounts.add(account)
|
||||
for account in msg.db_receivers_accounts.all():
|
||||
account = AccountDB.objects.get(id=account.id)
|
||||
msg.db_receivers_accounts.add(account)
|
||||
for account in msg.db_hide_from_accounts.all():
|
||||
account = AccountDB.objects.get(id=account.id)
|
||||
msg.db_hide_from_accounts.add(account)
|
||||
|
||||
ChannelDB = apps.get_model('comms', 'ChannelDB')
|
||||
for channel in ChannelDB.objects.all():
|
||||
for account in channel.db_subscriptions.all():
|
||||
account = AccountDB.objects.get(id=account.id)
|
||||
channel.db_account_subscriptions.add(account)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comms', '0013_auto_20170705_1726'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards)
|
||||
]
|
||||
43
evennia/comms/migrations/0015_auto_20170706_2041.py
Normal file
43
evennia/comms/migrations/0015_auto_20170706_2041.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-06 20:41
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, OperationalError, connection
|
||||
|
||||
|
||||
def _table_exists(db_cursor, tablename):
|
||||
"Returns bool if table exists or not"
|
||||
sql_check_exists = "SELECT * from %s;" % tablename
|
||||
try:
|
||||
db_cursor.execute(sql_check_exists)
|
||||
return True
|
||||
except OperationalError:
|
||||
return False
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comms', '0014_auto_20170705_1736'),
|
||||
]
|
||||
|
||||
db_cursor = connection.cursor()
|
||||
|
||||
if not _table_exists(db_cursor, "channels.channeldb_db_receivers_players"):
|
||||
# OBS - this is run BEFORE migrations are run!
|
||||
operations = []
|
||||
else:
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='channeldb',
|
||||
name='db_subscriptions', # this is now db_account_subscriptions
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='msg',
|
||||
name='db_receivers_players',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='msg',
|
||||
name='db_sender_players',
|
||||
),
|
||||
]
|
||||
|
|
@ -13,7 +13,7 @@ For non-persistent (and slightly faster) use one can also use the
|
|||
TempMsg, which mimics the Msg API but without actually saving to the
|
||||
database.
|
||||
|
||||
Channels are central objects that act as targets for Msgs. Players can
|
||||
Channels are central objects that act as targets for Msgs. Accounts can
|
||||
connect to channels by use of a ChannelConnect object (this object is
|
||||
necessary to easily be able to delete connections on the fly).
|
||||
"""
|
||||
|
|
@ -48,16 +48,18 @@ _CHANNELHANDLER = None
|
|||
class Msg(SharedMemoryModel):
|
||||
"""
|
||||
A single message. This model describes all ooc messages
|
||||
sent in-game, both to channels and between players.
|
||||
sent in-game, both to channels and between accounts.
|
||||
|
||||
The Msg class defines the following database fields (all
|
||||
accessed via specific handler methods):
|
||||
|
||||
- db_sender_players: Player senders
|
||||
- db_sender_accounts: Account senders
|
||||
- db_sender_objects: Object senders
|
||||
- db_sender_scripts: Script senders
|
||||
- db_sender_external: External senders (defined as string names)
|
||||
- db_receivers_players: Receiving players
|
||||
- db_receivers_accounts: Receiving accounts
|
||||
- db_receivers_objects: Receiving objects
|
||||
- db_receivers_scripts: Receiveing scripts
|
||||
- db_receivers_channels: Receiving channels
|
||||
- db_header: Header text
|
||||
- db_message: The actual message text
|
||||
|
|
@ -75,25 +77,31 @@ class Msg(SharedMemoryModel):
|
|||
# These databse fields are all set using their corresponding properties,
|
||||
# named same as the field, but withtout the db_* prefix.
|
||||
|
||||
# Sender is either a player, an object or an external sender, like
|
||||
# Sender is either an account, an object or an external sender, like
|
||||
# an IRC channel; normally there is only one, but if co-modification of
|
||||
# a message is allowed, there may be more than one "author"
|
||||
db_sender_players = models.ManyToManyField("players.PlayerDB", related_name='sender_player_set',
|
||||
null=True, blank=True, verbose_name='sender(player)', db_index=True)
|
||||
db_sender_accounts = models.ManyToManyField("accounts.AccountDB", related_name='sender_account_set',
|
||||
blank=True, verbose_name='sender(account)', db_index=True)
|
||||
|
||||
db_sender_objects = models.ManyToManyField("objects.ObjectDB", related_name='sender_object_set',
|
||||
null=True, blank=True, verbose_name='sender(object)', db_index=True)
|
||||
blank=True, verbose_name='sender(object)', db_index=True)
|
||||
db_sender_scripts = models.ManyToManyField("scripts.ScriptDB", related_name='sender_script_set',
|
||||
blank=True, verbose_name='sender(script)', db_index=True)
|
||||
db_sender_external = models.CharField('external sender', max_length=255, null=True, blank=True, db_index=True,
|
||||
help_text="identifier for external sender, for example a sender over an "
|
||||
"IRC connection (i.e. someone who doesn't have an exixtence in-game).")
|
||||
# The destination objects of this message. Stored as a
|
||||
# comma-separated string of object dbrefs. Can be defined along
|
||||
# with channels below.
|
||||
db_receivers_players = models.ManyToManyField('players.PlayerDB', related_name='receiver_player_set',
|
||||
null=True, blank=True, help_text="player receivers")
|
||||
db_receivers_accounts = models.ManyToManyField('accounts.AccountDB', related_name='receiver_account_set',
|
||||
blank=True, help_text="account receivers")
|
||||
|
||||
db_receivers_objects = models.ManyToManyField('objects.ObjectDB', related_name='receiver_object_set',
|
||||
null=True, blank=True, help_text="object receivers")
|
||||
blank=True, help_text="object receivers")
|
||||
db_receivers_scripts = models.ManyToManyField('scripts.ScriptDB', related_name='receiver_script_set',
|
||||
blank=True, help_text="script_receivers")
|
||||
db_receivers_channels = models.ManyToManyField("ChannelDB", related_name='channel_set',
|
||||
null=True, blank=True, help_text="channel recievers")
|
||||
blank=True, help_text="channel recievers")
|
||||
|
||||
# header could be used for meta-info about the message if your system needs
|
||||
# it, or as a separate store for the mail subject line maybe.
|
||||
|
|
@ -106,12 +114,14 @@ class Msg(SharedMemoryModel):
|
|||
db_lock_storage = models.TextField('locks', blank=True,
|
||||
help_text='access locks on this message.')
|
||||
|
||||
# these can be used to filter/hide a given message from supplied objects/players/channels
|
||||
db_hide_from_players = models.ManyToManyField("players.PlayerDB", related_name='hide_from_players_set', null=True, blank=True)
|
||||
db_hide_from_objects = models.ManyToManyField("objects.ObjectDB", related_name='hide_from_objects_set', null=True, blank=True)
|
||||
db_hide_from_channels = models.ManyToManyField("ChannelDB", related_name='hide_from_channels_set', null=True, blank=True)
|
||||
# these can be used to filter/hide a given message from supplied objects/accounts/channels
|
||||
db_hide_from_accounts = models.ManyToManyField("accounts.AccountDB", related_name='hide_from_accounts_set', blank=True)
|
||||
db_hide_from_accounts = models.ManyToManyField("accounts.AccountDB", related_name='hide_from_accounts_set', blank=True)
|
||||
|
||||
db_tags = models.ManyToManyField(Tag, null=True, blank=True,
|
||||
db_hide_from_objects = models.ManyToManyField("objects.ObjectDB", related_name='hide_from_objects_set', blank=True)
|
||||
db_hide_from_channels = models.ManyToManyField("ChannelDB", related_name='hide_from_channels_set', blank=True)
|
||||
|
||||
db_tags = models.ManyToManyField(Tag, blank=True,
|
||||
help_text='tags on this message. Tags are simple string markers to identify, group and alias messages.')
|
||||
|
||||
# Database manager
|
||||
|
|
@ -146,8 +156,9 @@ class Msg(SharedMemoryModel):
|
|||
#@property
|
||||
def __senders_get(self):
|
||||
"Getter. Allows for value = self.sender"
|
||||
return list(self.db_sender_players.all()) + \
|
||||
return list(self.db_sender_accounts.all()) + \
|
||||
list(self.db_sender_objects.all()) + \
|
||||
list(self.db_sender_scripts.all()) + \
|
||||
self.extra_senders
|
||||
|
||||
#@sender.setter
|
||||
|
|
@ -166,14 +177,17 @@ class Msg(SharedMemoryModel):
|
|||
clsname = sender.__dbclass__.__name__
|
||||
if clsname == "ObjectDB":
|
||||
self.db_sender_objects.add(sender)
|
||||
elif clsname == "PlayerDB":
|
||||
self.db_sender_players.add(sender)
|
||||
elif clsname == "AccountDB":
|
||||
self.db_sender_accounts.add(sender)
|
||||
elif clsname == "ScriptDB":
|
||||
self.db_sender_scripts.add(sender)
|
||||
|
||||
#@sender.deleter
|
||||
def __senders_del(self):
|
||||
"Deleter. Clears all senders"
|
||||
self.db_sender_players.clear()
|
||||
self.db_sender_accounts.clear()
|
||||
self.db_sender_objects.clear()
|
||||
self.db_sender_scripts.clear()
|
||||
self.db_sender_external = ""
|
||||
self.extra_senders = []
|
||||
self.save()
|
||||
|
|
@ -184,7 +198,7 @@ class Msg(SharedMemoryModel):
|
|||
Remove a single sender or a list of senders.
|
||||
|
||||
Args:
|
||||
senders (Player, Object, str or list): Senders to remove.
|
||||
senders (Account, Object, str or list): Senders to remove.
|
||||
|
||||
"""
|
||||
for sender in make_iter(senders):
|
||||
|
|
@ -198,17 +212,22 @@ class Msg(SharedMemoryModel):
|
|||
clsname = sender.__dbclass__.__name__
|
||||
if clsname == "ObjectDB":
|
||||
self.db_sender_objects.remove(sender)
|
||||
elif clsname == "PlayerDB":
|
||||
self.db_sender_players.remove(sender)
|
||||
elif clsname == "AccountDB":
|
||||
self.db_sender_accounts.remove(sender)
|
||||
elif clsname == "ScriptDB":
|
||||
self.db_sender_accounts.remove(sender)
|
||||
|
||||
# receivers property
|
||||
#@property
|
||||
def __receivers_get(self):
|
||||
"""
|
||||
Getter. Allows for value = self.receivers.
|
||||
Returns three lists of receivers: players, objects and channels.
|
||||
Returns four lists of receivers: accounts, objects, scripts and channels.
|
||||
"""
|
||||
return list(self.db_receivers_players.all()) + list(self.db_receivers_objects.all())
|
||||
return list(self.db_receivers_accounts.all()) + \
|
||||
list(self.db_receivers_objects.all()) + \
|
||||
list(self.db_receivers_scripts.all()) + \
|
||||
list(self.db_receivers_channels.all())
|
||||
|
||||
#@receivers.setter
|
||||
def __receivers_set(self, receivers):
|
||||
|
|
@ -224,14 +243,21 @@ class Msg(SharedMemoryModel):
|
|||
clsname = receiver.__dbclass__.__name__
|
||||
if clsname == "ObjectDB":
|
||||
self.db_receivers_objects.add(receiver)
|
||||
elif clsname == "PlayerDB":
|
||||
self.db_receivers_players.add(receiver)
|
||||
elif clsname == "AccountDB":
|
||||
self.db_receivers_accounts.add(receiver)
|
||||
elif clsname == "ScriptDB":
|
||||
self.db_receivers_scripts.add(receiver)
|
||||
elif clsname == "ChannelDB":
|
||||
self.db_receivers_channels.add(receiver)
|
||||
|
||||
|
||||
#@receivers.deleter
|
||||
def __receivers_del(self):
|
||||
"Deleter. Clears all receivers"
|
||||
self.db_receivers_players.clear()
|
||||
self.db_receivers_accounts.clear()
|
||||
self.db_receivers_objects.clear()
|
||||
self.db_receivers_scripts.clear()
|
||||
self.db_receivers_channels.clear()
|
||||
self.save()
|
||||
receivers = property(__receivers_get, __receivers_set, __receivers_del)
|
||||
|
||||
|
|
@ -240,7 +266,7 @@ class Msg(SharedMemoryModel):
|
|||
Remove a single receiver or a list of receivers.
|
||||
|
||||
Args:
|
||||
receivers (Player, Object, Channel or list): Receiver to remove.
|
||||
receivers (Account, Object, Script, Channel or list): Receiver to remove.
|
||||
|
||||
"""
|
||||
for receiver in make_iter(receivers):
|
||||
|
|
@ -251,8 +277,12 @@ class Msg(SharedMemoryModel):
|
|||
clsname = receiver.__dbclass__.__name__
|
||||
if clsname == "ObjectDB":
|
||||
self.db_receivers_objects.remove(receiver)
|
||||
elif clsname == "PlayerDB":
|
||||
self.db_receivers_players.remove(receiver)
|
||||
elif clsname == "AccountDB":
|
||||
self.db_receivers_accounts.remove(receiver)
|
||||
elif clsname == "ScriptDB":
|
||||
self.db_receivers_scripts.remove(receiver)
|
||||
elif clsname == "ChannelDB":
|
||||
self.db_receivers_channels.remove(receiver)
|
||||
|
||||
# channels property
|
||||
#@property
|
||||
|
|
@ -279,9 +309,9 @@ class Msg(SharedMemoryModel):
|
|||
def __hide_from_get(self):
|
||||
"""
|
||||
Getter. Allows for value = self.hide_from.
|
||||
Returns 3 lists of players, objects and channels
|
||||
Returns 3 lists of accounts, objects and channels
|
||||
"""
|
||||
return self.db_hide_from_players.all(), self.db_hide_from_objects.all(), self.db_hide_from_channels.all()
|
||||
return self.db_hide_from_accounts.all(), self.db_hide_from_objects.all(), self.db_hide_from_channels.all()
|
||||
|
||||
#@hide_from_sender.setter
|
||||
def __hide_from_set(self, hiders):
|
||||
|
|
@ -292,8 +322,8 @@ class Msg(SharedMemoryModel):
|
|||
if not hasattr(hider, "__dbclass__"):
|
||||
raise ValueError("This is a not a typeclassed object!")
|
||||
clsname = hider.__dbclass__.__name__
|
||||
if clsname == "PlayerDB":
|
||||
self.db_hide_from_players.add(hider.__dbclass__)
|
||||
if clsname == "AccountDB":
|
||||
self.db_hide_from_accounts.add(hider.__dbclass__)
|
||||
elif clsname == "ObjectDB":
|
||||
self.db_hide_from_objects.add(hider.__dbclass__)
|
||||
elif clsname == "ChannelDB":
|
||||
|
|
@ -302,7 +332,7 @@ class Msg(SharedMemoryModel):
|
|||
#@hide_from_sender.deleter
|
||||
def __hide_from_del(self):
|
||||
"Deleter. Allows for del self.hide_from_senders"
|
||||
self.db_hide_from_players.clear()
|
||||
self.db_hide_from_accounts.clear()
|
||||
self.db_hide_from_objects.clear()
|
||||
self.db_hide_from_channels.clear()
|
||||
self.save()
|
||||
|
|
@ -323,7 +353,7 @@ class Msg(SharedMemoryModel):
|
|||
Checks lock access.
|
||||
|
||||
Args:
|
||||
accessing_obj (Object or Player): The object trying to gain access.
|
||||
accessing_obj (Object or Account): The object trying to gain access.
|
||||
access_type (str, optional): The type of lock access to check.
|
||||
default (bool): Fallback to use if `access_type` lock is not defined.
|
||||
|
||||
|
|
@ -353,13 +383,13 @@ class TempMsg(object):
|
|||
|
||||
Args:
|
||||
senders (any or list, optional): Senders of the message.
|
||||
receivers (Player, Object, Channel or list, optional): Receivers of this message.
|
||||
receivers (Account, Object, Channel or list, optional): Receivers of this message.
|
||||
channels (Channel or list, optional): Channels to send to.
|
||||
message (str, optional): Message to send.
|
||||
header (str, optional): Header of message.
|
||||
type (str, optional): Message class, if any.
|
||||
lockstring (str, optional): Lock for the message.
|
||||
hide_from (Player, Object, Channel or list, optional): Entities to hide this message from.
|
||||
hide_from (Account, Object, Channel or list, optional): Entities to hide this message from.
|
||||
|
||||
"""
|
||||
self.senders = senders and make_iter(senders) or []
|
||||
|
|
@ -389,7 +419,7 @@ class TempMsg(object):
|
|||
Remove a sender or a list of senders.
|
||||
|
||||
Args:
|
||||
sender (Object, Player, str or list): Senders to remove.
|
||||
sender (Object, Account, str or list): Senders to remove.
|
||||
|
||||
"""
|
||||
for o in make_iter(sender):
|
||||
|
|
@ -403,7 +433,7 @@ class TempMsg(object):
|
|||
Remove a receiver or a list of receivers
|
||||
|
||||
Args:
|
||||
receiver (Object, Player, Channel, str or list): Receivers to remove.
|
||||
receiver (Object, Account, Channel, str or list): Receivers to remove.
|
||||
"""
|
||||
|
||||
for o in make_iter(receiver):
|
||||
|
|
@ -417,7 +447,7 @@ class TempMsg(object):
|
|||
Checks lock access.
|
||||
|
||||
Args:
|
||||
accessing_obj (Object or Player): The object trying to gain access.
|
||||
accessing_obj (Object or Account): The object trying to gain access.
|
||||
access_type (str, optional): The type of lock access to check.
|
||||
default (bool): Fallback to use if `access_type` lock is not defined.
|
||||
|
||||
|
|
@ -439,7 +469,7 @@ class SubscriptionHandler(object):
|
|||
"""
|
||||
This handler manages subscriptions to the
|
||||
channel and hides away which type of entity is
|
||||
subscribing (Player or Object)
|
||||
subscribing (Account or Object)
|
||||
"""
|
||||
def __init__(self, obj):
|
||||
"""
|
||||
|
|
@ -453,7 +483,7 @@ class SubscriptionHandler(object):
|
|||
self._cache = None
|
||||
|
||||
def _recache(self):
|
||||
self._cache = {player : True for player in self.obj.db_subscriptions.all()}
|
||||
self._cache = {account : True for account in self.obj.db_account_subscriptions.all()}
|
||||
self._cache.update({obj : True for obj in self.obj.db_object_subscriptions.all()})
|
||||
|
||||
def has(self, entity):
|
||||
|
|
@ -461,12 +491,12 @@ class SubscriptionHandler(object):
|
|||
Check if the given entity subscribe to this channel
|
||||
|
||||
Args:
|
||||
entity (str, Player or Object): The entity to return. If
|
||||
entity (str, Account or Object): The entity to return. If
|
||||
a string, it assumed to be the key or the #dbref
|
||||
of the entity.
|
||||
|
||||
Returns:
|
||||
subscriber (Player, Object or None): The given
|
||||
subscriber (Account, Object or None): The given
|
||||
subscriber.
|
||||
|
||||
"""
|
||||
|
|
@ -479,7 +509,7 @@ class SubscriptionHandler(object):
|
|||
Subscribe an entity to this channel.
|
||||
|
||||
Args:
|
||||
entity (Player, Object or list): The entity or
|
||||
entity (Account, Object or list): The entity or
|
||||
list of entities to subscribe to this channel.
|
||||
|
||||
Note:
|
||||
|
|
@ -497,8 +527,8 @@ class SubscriptionHandler(object):
|
|||
# chooses the right type
|
||||
if clsname == "ObjectDB":
|
||||
self.obj.db_object_subscriptions.add(subscriber)
|
||||
elif clsname == "PlayerDB":
|
||||
self.obj.db_subscriptions.add(subscriber)
|
||||
elif clsname == "AccountDB":
|
||||
self.obj.db_account_subscriptions.add(subscriber)
|
||||
_CHANNELHANDLER.cached_cmdsets.pop(subscriber, None)
|
||||
self._recache()
|
||||
|
||||
|
|
@ -507,7 +537,7 @@ class SubscriptionHandler(object):
|
|||
Remove a subscriber from the channel.
|
||||
|
||||
Args:
|
||||
entity (Player, Object or list): The entity or
|
||||
entity (Account, Object or list): The entity or
|
||||
entities to un-subscribe from the channel.
|
||||
|
||||
"""
|
||||
|
|
@ -518,8 +548,8 @@ class SubscriptionHandler(object):
|
|||
if subscriber:
|
||||
clsname = subscriber.__dbclass__.__name__
|
||||
# chooses the right type
|
||||
if clsname == "PlayerDB":
|
||||
self.obj.db_subscriptions.remove(entity)
|
||||
if clsname == "AccountDB":
|
||||
self.obj.db_account_subscriptions.remove(entity)
|
||||
elif clsname == "ObjectDB":
|
||||
self.obj.db_object_subscriptions.remove(entity)
|
||||
_CHANNELHANDLER.cached_cmdsets.pop(subscriber, None)
|
||||
|
|
@ -531,7 +561,7 @@ class SubscriptionHandler(object):
|
|||
|
||||
Returns:
|
||||
subscribers (list): The subscribers. This
|
||||
may be a mix of Players and Objects!
|
||||
may be a mix of Accounts and Objects!
|
||||
|
||||
"""
|
||||
if self._cache is None:
|
||||
|
|
@ -540,17 +570,17 @@ class SubscriptionHandler(object):
|
|||
|
||||
def online(self):
|
||||
"""
|
||||
Get all online players from our cache
|
||||
Get all online accounts from our cache
|
||||
Returns:
|
||||
subscribers (list): Subscribers who are online or
|
||||
are puppeted by an online player.
|
||||
are puppeted by an online account.
|
||||
"""
|
||||
subs = []
|
||||
for obj in self.all():
|
||||
if hasattr(obj, 'player'):
|
||||
if not obj.player:
|
||||
if hasattr(obj, 'account'):
|
||||
if not obj.account:
|
||||
continue
|
||||
obj = obj.player
|
||||
obj = obj.account
|
||||
if not obj.is_connected:
|
||||
continue
|
||||
subs.append(obj)
|
||||
|
|
@ -561,7 +591,7 @@ class SubscriptionHandler(object):
|
|||
Remove all subscribers from channel.
|
||||
|
||||
"""
|
||||
self.obj.db_subscriptions.clear()
|
||||
self.obj.db_account_subscriptions.clear()
|
||||
self.obj.db_object_subscriptions.clear()
|
||||
self._cache = None
|
||||
|
||||
|
|
@ -574,16 +604,15 @@ class ChannelDB(TypedObject):
|
|||
The Channel class defines the following database fields
|
||||
beyond the ones inherited from TypedObject:
|
||||
|
||||
- db_subscriptions: The Player subscriptions (this is the most
|
||||
usual case, named this way for legacy.
|
||||
- db_account_subscriptions: The Account subscriptions.
|
||||
- db_object_subscriptions: The Object subscriptions.
|
||||
|
||||
"""
|
||||
db_subscriptions = models.ManyToManyField("players.PlayerDB",
|
||||
related_name="subscription_set", null=True, blank=True, verbose_name='subscriptions', db_index=True)
|
||||
db_account_subscriptions = models.ManyToManyField("accounts.AccountDB",
|
||||
related_name="account_subscription_set", blank=True, verbose_name='account subscriptions', db_index=True)
|
||||
|
||||
db_object_subscriptions = models.ManyToManyField("objects.ObjectDB",
|
||||
related_name="object_subscription_set", null=True, blank=True, verbose_name='subscriptions', db_index=True)
|
||||
related_name="object_subscription_set", blank=True, verbose_name='object subscriptions', db_index=True)
|
||||
|
||||
# Database manager
|
||||
objects = managers.ChannelDBManager()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ things you want from here into your game folder and change them there.
|
|||
Meant as a starting point for a more fleshed-out system.
|
||||
* Clothing (BattleJenkins 2017) - A layered clothing system with
|
||||
slots for different types of garments auto-showing in description.
|
||||
* Color-markups (Griatch, 2017) - Alternative in-game color markups.
|
||||
* Custom gametime (Griatch, vlgeoff 2017) - Implements Evennia's
|
||||
gametime module but for custom game world-specific calendars.
|
||||
* Dice (Griatch 2012) - A fully featured dice rolling system.
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ class CmdTradeBase(Command):
|
|||
if ':' in self.args:
|
||||
self.args, self.emote = [part.strip() for part in self.args.rsplit(":", 1)]
|
||||
self.str_caller = 'You say, "' + self.emote + '"\n [%s]'
|
||||
if self.caller.has_player:
|
||||
if self.caller.has_account:
|
||||
self.str_other = '|c%s|n says, "' % self.caller.key + self.emote + '"\n [%s]'
|
||||
else:
|
||||
self.str_other = '%s says, "' % self.caller.key + self.emote + '"\n [%s]'
|
||||
|
|
@ -766,7 +766,7 @@ class CmdTrade(Command):
|
|||
if ':' in self.args:
|
||||
self.args, emote = [part.strip() for part in self.args.rsplit(":", 1)]
|
||||
selfemote = 'You say, "%s"\n ' % emote
|
||||
if self.caller.has_player:
|
||||
if self.caller.has_account:
|
||||
theiremote = '|c%s|n says, "%s"\n ' % (self.caller.key, emote)
|
||||
else:
|
||||
theiremote = '%s says, "%s"\n ' % (self.caller.key, emote)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ necessary anymore - the ooclook and @charcreate commands in that mode
|
|||
replaces this module with better functionality. This remains here for
|
||||
inspiration.
|
||||
|
||||
This is a simple character creation commandset for the Player level.
|
||||
It shows some more info and gives the Player the option to create a
|
||||
This is a simple character creation commandset for the Account level.
|
||||
It shows some more info and gives the Account the option to create a
|
||||
character without any more customizations than their name (further
|
||||
options are unique for each game anyway).
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ cmdset.
|
|||
Installation:
|
||||
|
||||
Import this module to `mygame/commands/default_cmdsets.py` and
|
||||
add `chargen.OOCCMdSetCharGen` to the `PlayerCmdSet` class
|
||||
add `chargen.OOCCMdSetCharGen` to the `AccountCmdSet` class
|
||||
(it says where to add it). Reload.
|
||||
|
||||
"""
|
||||
|
|
@ -39,7 +39,7 @@ class CmdOOCLook(default_cmds.CmdLook):
|
|||
look
|
||||
look <character>
|
||||
|
||||
This is an OOC version of the look command. Since a Player doesn't
|
||||
This is an OOC version of the look command. Since an Account doesn't
|
||||
have an in-game existence, there is no concept of location or
|
||||
"self".
|
||||
|
||||
|
|
@ -56,24 +56,24 @@ class CmdOOCLook(default_cmds.CmdLook):
|
|||
"""
|
||||
Implements the ooc look command
|
||||
|
||||
We use an attribute _character_dbrefs on the player in order
|
||||
We use an attribute _character_dbrefs on the account in order
|
||||
to figure out which characters are "theirs". A drawback of this
|
||||
is that only the CmdCharacterCreate command adds this attribute,
|
||||
and thus e.g. player #1 will not be listed (although it will work).
|
||||
and thus e.g. account #1 will not be listed (although it will work).
|
||||
Existence in this list does not depend on puppeting rights though,
|
||||
that is checked by the @ic command directly.
|
||||
"""
|
||||
|
||||
# making sure caller is really a player
|
||||
# making sure caller is really an account
|
||||
self.character = None
|
||||
if utils.inherits_from(self.caller, "evennia.objects.objects.Object"):
|
||||
# An object of some type is calling. Convert to player.
|
||||
# An object of some type is calling. Convert to account.
|
||||
self.character = self.caller
|
||||
if hasattr(self.caller, "player"):
|
||||
self.caller = self.caller.player
|
||||
if hasattr(self.caller, "account"):
|
||||
self.caller = self.caller.account
|
||||
|
||||
if not self.character:
|
||||
# ooc mode, we are players
|
||||
# ooc mode, we are accounts
|
||||
|
||||
avail_chars = self.caller.db._character_dbrefs
|
||||
if self.args:
|
||||
|
|
@ -139,13 +139,13 @@ class CmdOOCCharacterCreate(Command):
|
|||
attribute on ourselves to remember it.
|
||||
"""
|
||||
|
||||
# making sure caller is really a player
|
||||
# making sure caller is really an account
|
||||
self.character = None
|
||||
if utils.inherits_from(self.caller, "evennia.objects.objects.Object"):
|
||||
# An object of some type is calling. Convert to player.
|
||||
# An object of some type is calling. Convert to account.
|
||||
self.character = self.caller
|
||||
if hasattr(self.caller, "player"):
|
||||
self.caller = self.caller.player
|
||||
if hasattr(self.caller, "account"):
|
||||
self.caller = self.caller.account
|
||||
|
||||
if not self.args:
|
||||
self.caller.msg("Usage: create <character name>")
|
||||
|
|
@ -161,8 +161,8 @@ class CmdOOCCharacterCreate(Command):
|
|||
if not new_character:
|
||||
self.caller.msg("|rThe Character couldn't be created. This is a bug. Please contact an admin.")
|
||||
return
|
||||
# make sure to lock the character to only be puppeted by this player
|
||||
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
|
||||
# make sure to lock the character to only be puppeted by this account
|
||||
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)" %
|
||||
(new_character.id, self.caller.id))
|
||||
|
||||
# save dbref
|
||||
|
|
@ -175,7 +175,7 @@ class CmdOOCCharacterCreate(Command):
|
|||
self.caller.msg("|gThe character |c%s|g was successfully created!" % charname)
|
||||
|
||||
|
||||
class OOCCmdSetCharGen(default_cmds.PlayerCmdSet):
|
||||
class OOCCmdSetCharGen(default_cmds.AccountCmdSet):
|
||||
"""
|
||||
Extends the default OOC cmdset.
|
||||
"""
|
||||
|
|
|
|||
238
evennia/contrib/color_markups.py
Normal file
238
evennia/contrib/color_markups.py
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
"""
|
||||
Color markups
|
||||
|
||||
Contribution, Griatch 2017
|
||||
|
||||
Additional color markup styles for Evennia (extending or replacing the default |r, |234 etc).
|
||||
|
||||
|
||||
Installation:
|
||||
|
||||
Import the desired style variables from this module into mygame/server/conf/settings.py and add them
|
||||
to these settings variables. Each are specified as a list, and multiple such lists can be added to
|
||||
each variable to support multiple formats. Note that list order affects which regexes are applied
|
||||
first. You must restart both Portal and Server for color tags to update.
|
||||
|
||||
Assign to the following settings variables:
|
||||
|
||||
COLOR_ANSI_EXTRA_MAP - a mapping between regexes and ANSI colors
|
||||
COLOR_XTERM256_EXTRA_FG - regex for defining XTERM256 foreground colors
|
||||
COLOR_XTERM256_EXTRA_BG - regex for defining XTERM256 background colors
|
||||
COLOR_XTERM256_EXTRA_GFG - regex for defining XTERM256 grayscale foreground colors
|
||||
COLOR_XTERM256_EXTRA_GBG - regex for defining XTERM256 grayscale background colors
|
||||
COLOR_ANSI_BRIGHT_BG_EXTRA_MAP = ANSI does not support bright backgrounds; we fake
|
||||
this by mapping ANSI markup to matching bright XTERM256 backgrounds
|
||||
|
||||
COLOR_NO_DEFAULT - Set True/False. If False (default), extend the default markup, otherwise
|
||||
replace it completely.
|
||||
|
||||
|
||||
To add the {- "curly-bracket" style, add the following to your settings file, then reboot both
|
||||
Server and Portal:
|
||||
|
||||
from evennia.contrib import color_markups
|
||||
COLOR_ANSI_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_EXTRA_MAP
|
||||
COLOR_XTERM256_EXTRA_FG = color_markups.CURLY_COLOR_XTERM256_EXTRA_FG
|
||||
COLOR_XTERM256_EXTRA_BG = color_markups.CURLY_COLOR_XTERM256_EXTRA_BG
|
||||
COLOR_XTERM256_EXTRA_GFG = color_markups.CURLY_COLOR_XTERM256_EXTRA_GFG
|
||||
COLOR_XTERM256_EXTRA_GBG = color_markups.CURLY_COLOR_XTERM256_EXTRA_GBG
|
||||
COLOR_ANSI_BRIGHT_BG_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BG_EXTRA_MAP
|
||||
|
||||
|
||||
To add the %c- "mux/mush" style, add the following to your settings file, then reboot both Server
|
||||
and Portal:
|
||||
|
||||
from evennia.contrib import color_markups
|
||||
COLOR_ANSI_EXTRA_MAP = color_markups.MUX_COLOR_ANSI_EXTRA_MAP
|
||||
COLOR_XTERM256_EXTRA_FG = color_markups.MUX_COLOR_XTERM256_EXTRA_FG
|
||||
COLOR_XTERM256_EXTRA_BG = color_markups.MUX_COLOR_XTERM256_EXTRA_BG
|
||||
COLOR_XTERM256_EXTRA_GFG = color_markups.MUX_COLOR_XTERM256_EXTRA_GFG
|
||||
COLOR_XTERM256_EXTRA_GBG = color_markups.MUX_COLOR_XTERM256_EXTRA_GBG
|
||||
COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP
|
||||
|
||||
|
||||
"""
|
||||
|
||||
# ANSI constants (copied from evennia.utils.ansi to avoid import)
|
||||
|
||||
_ANSI_BEEP = "\07"
|
||||
_ANSI_ESCAPE = "\033"
|
||||
_ANSI_NORMAL = "\033[0m"
|
||||
|
||||
_ANSI_UNDERLINE = "\033[4m"
|
||||
_ANSI_HILITE = "\033[1m"
|
||||
_ANSI_UNHILITE = "\033[22m"
|
||||
_ANSI_BLINK = "\033[5m"
|
||||
_ANSI_INVERSE = "\033[7m"
|
||||
_ANSI_INV_HILITE = "\033[1;7m"
|
||||
_ANSI_INV_BLINK = "\033[7;5m"
|
||||
_ANSI_BLINK_HILITE = "\033[1;5m"
|
||||
_ANSI_INV_BLINK_HILITE = "\033[1;5;7m"
|
||||
|
||||
# Foreground colors
|
||||
_ANSI_BLACK = "\033[30m"
|
||||
_ANSI_RED = "\033[31m"
|
||||
_ANSI_GREEN = "\033[32m"
|
||||
_ANSI_YELLOW = "\033[33m"
|
||||
_ANSI_BLUE = "\033[34m"
|
||||
_ANSI_MAGENTA = "\033[35m"
|
||||
_ANSI_CYAN = "\033[36m"
|
||||
_ANSI_WHITE = "\033[37m"
|
||||
|
||||
# Background colors
|
||||
_ANSI_BACK_BLACK = "\033[40m"
|
||||
_ANSI_BACK_RED = "\033[41m"
|
||||
_ANSI_BACK_GREEN = "\033[42m"
|
||||
_ANSI_BACK_YELLOW = "\033[43m"
|
||||
_ANSI_BACK_BLUE = "\033[44m"
|
||||
_ANSI_BACK_MAGENTA = "\033[45m"
|
||||
_ANSI_BACK_CYAN = "\033[46m"
|
||||
_ANSI_BACK_WHITE = "\033[47m"
|
||||
|
||||
# Formatting Characters
|
||||
_ANSI_RETURN = "\r\n"
|
||||
_ANSI_TAB = "\t"
|
||||
_ANSI_SPACE = " "
|
||||
|
||||
|
||||
#############################################################
|
||||
#
|
||||
# {- style MUD markup (old Evennia default). This is
|
||||
# basically identical to the default |-style except using
|
||||
# a curly bracket instead. This was removed because {}
|
||||
# are used in Python string formatting.
|
||||
#
|
||||
# {r, {R - bright/dark red foreground
|
||||
# {[r, {[R - bright/dark red background
|
||||
# {500, {[500 - XTERM256 red foreground/background
|
||||
# {=w, {[=w - XTERM256 greyscale foreground/background
|
||||
#
|
||||
#############################################################
|
||||
|
||||
CURLY_COLOR_ANSI_EXTRA_MAP = [
|
||||
(r'{n', _ANSI_NORMAL), # reset
|
||||
(r'{/', _ANSI_RETURN), # line break
|
||||
(r'{-', _ANSI_TAB), # tab
|
||||
(r'{_', _ANSI_SPACE), # space
|
||||
(r'{*', _ANSI_INVERSE), # invert
|
||||
(r'{^', _ANSI_BLINK), # blinking text (very annoying and not supported by all clients)
|
||||
(r'{u', _ANSI_UNDERLINE), # underline
|
||||
|
||||
(r'{r', _ANSI_HILITE + _ANSI_RED),
|
||||
(r'{g', _ANSI_HILITE + _ANSI_GREEN),
|
||||
(r'{y', _ANSI_HILITE + _ANSI_YELLOW),
|
||||
(r'{b', _ANSI_HILITE + _ANSI_BLUE),
|
||||
(r'{m', _ANSI_HILITE + _ANSI_MAGENTA),
|
||||
(r'{c', _ANSI_HILITE + _ANSI_CYAN),
|
||||
(r'{w', _ANSI_HILITE + _ANSI_WHITE), # pure white
|
||||
(r'{x', _ANSI_HILITE + _ANSI_BLACK), # dark grey
|
||||
|
||||
(r'{R', _ANSI_HILITE + _ANSI_RED),
|
||||
(r'{G', _ANSI_HILITE + _ANSI_GREEN),
|
||||
(r'{Y', _ANSI_HILITE + _ANSI_YELLOW),
|
||||
(r'{B', _ANSI_HILITE + _ANSI_BLUE),
|
||||
(r'{M', _ANSI_HILITE + _ANSI_MAGENTA),
|
||||
(r'{C', _ANSI_HILITE + _ANSI_CYAN),
|
||||
(r'{W', _ANSI_HILITE + _ANSI_WHITE), # light grey
|
||||
(r'{X', _ANSI_HILITE + _ANSI_BLACK), # pure black
|
||||
|
||||
# hilight-able colors
|
||||
(r'{h', _ANSI_HILITE),
|
||||
(r'{H', _ANSI_UNHILITE),
|
||||
|
||||
(r'{!R', _ANSI_RED),
|
||||
(r'{!G', _ANSI_GREEN),
|
||||
(r'{!Y', _ANSI_YELLOW),
|
||||
(r'{!B', _ANSI_BLUE),
|
||||
(r'{!M', _ANSI_MAGENTA),
|
||||
(r'{!C', _ANSI_CYAN),
|
||||
(r'{!W', _ANSI_WHITE), # light grey
|
||||
(r'{!X', _ANSI_BLACK), # pure black
|
||||
|
||||
# normal ANSI backgrounds
|
||||
(r'{[R', _ANSI_BACK_RED),
|
||||
(r'{[G', _ANSI_BACK_GREEN),
|
||||
(r'{[Y', _ANSI_BACK_YELLOW),
|
||||
(r'{[B', _ANSI_BACK_BLUE),
|
||||
(r'{[M', _ANSI_BACK_MAGENTA),
|
||||
(r'{[C', _ANSI_BACK_CYAN),
|
||||
(r'{[W', _ANSI_BACK_WHITE), # light grey background
|
||||
(r'{[X', _ANSI_BACK_BLACK), # pure black background
|
||||
]
|
||||
|
||||
CURLY_COLOR_XTERM256_EXTRA_FG = [r'\{([0-5])([0-5])([0-5])'] # |123 - foreground colour
|
||||
CURLY_COLOR_XTERM256_EXTRA_BG = [r'\{\[([0-5])([0-5])([0-5])'] # |[123 - background colour
|
||||
CURLY_COLOR_XTERM256_EXTRA_GFG = [r'\{=([a-z])'] # |=a - greyscale foreground
|
||||
CURLY_COLOR_XTERM256_EXTRA_GBG = [r'\{\[=([a-z])'] # |[=a - greyscale background
|
||||
|
||||
CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
|
||||
(r'{[r', r'{[500'),
|
||||
(r'{[g', r'{[050'),
|
||||
(r'{[y', r'{[550'),
|
||||
(r'{[b', r'{[005'),
|
||||
(r'{[m', r'{[505'),
|
||||
(r'{[c', r'{[055'),
|
||||
(r'{[w', r'{[555'), # white background
|
||||
(r'{[x', r'{[222'), # dark grey background
|
||||
]
|
||||
|
||||
|
||||
#############################################################
|
||||
#
|
||||
# %c - MUX/MUSH style markup. This was Evennia's first
|
||||
# color markup style. It was phased out due to % being used
|
||||
# in Python formatting operations.
|
||||
#
|
||||
# %ch%cr, %cr - bright/dark red foreground
|
||||
# %ch%cR, %cR- bright/dark red background
|
||||
# %c500, %c[500 - XTERM256 red foreground/background
|
||||
# %c=w, %c[=w - XTERM256 greyscale foreground/background
|
||||
#
|
||||
#############################################################
|
||||
|
||||
MUX_COLOR_ANSI_EXTRA_MAP = [
|
||||
(r'%cn', _ANSI_NORMAL), # reset
|
||||
(r'%ch', _ANSI_HILITE), # highlight
|
||||
(r'%r', _ANSI_RETURN), # line break
|
||||
(r'%R', _ANSI_RETURN), #
|
||||
(r'%t', _ANSI_TAB), # tab
|
||||
(r'%T', _ANSI_TAB), #
|
||||
(r'%b', _ANSI_SPACE), # space
|
||||
(r'%B', _ANSI_SPACE),
|
||||
(r'%cf', _ANSI_BLINK), # annoying and not supported by all clients
|
||||
(r'%ci', _ANSI_INVERSE), # invert
|
||||
|
||||
(r'%cr', _ANSI_RED),
|
||||
(r'%cg', _ANSI_GREEN),
|
||||
(r'%cy', _ANSI_YELLOW),
|
||||
(r'%cb', _ANSI_BLUE),
|
||||
(r'%cm', _ANSI_MAGENTA),
|
||||
(r'%cc', _ANSI_CYAN),
|
||||
(r'%cw', _ANSI_WHITE),
|
||||
(r'%cx', _ANSI_BLACK),
|
||||
|
||||
(r'%cR', _ANSI_BACK_RED),
|
||||
(r'%cG', _ANSI_BACK_GREEN),
|
||||
(r'%cY', _ANSI_BACK_YELLOW),
|
||||
(r'%cB', _ANSI_BACK_BLUE),
|
||||
(r'%cM', _ANSI_BACK_MAGENTA),
|
||||
(r'%cC', _ANSI_BACK_CYAN),
|
||||
(r'%cW', _ANSI_BACK_WHITE),
|
||||
(r'%cX', _ANSI_BACK_BLACK)
|
||||
]
|
||||
|
||||
MUX_COLOR_XTERM256_EXTRA_FG = [r'%c([0-5])([0-5])([0-5])'] # %c123 - foreground colour
|
||||
MUX_COLOR_XTERM256_EXTRA_BG = [r'%c\[([0-5])([0-5])([0-5])'] # %c[123 - background colour
|
||||
MUX_COLOR_XTERM256_EXTRA_GFG = [r'%c=([a-z])'] # %c=a - greyscale foreground
|
||||
MUX_COLOR_XTERM256_EXTRA_GBG = [r'%c\[=([a-z])'] # %c[=a - greyscale background
|
||||
|
||||
MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
|
||||
(r'%ch%cR', r'%c[500'),
|
||||
(r'%ch%cG', r'%c[050'),
|
||||
(r'%ch%cY', r'%c[550'),
|
||||
(r'%ch%cB', r'%c[005'),
|
||||
(r'%ch%cM', r'%c[505'),
|
||||
(r'%ch%cC', r'%c[055'),
|
||||
(r'%ch%cW', r'%c[555'), # white background
|
||||
(r'%ch%cX', r'%c[222'), # dark grey background
|
||||
]
|
||||
|
|
@ -13,7 +13,7 @@ from twisted.web.http_headers import Headers
|
|||
from twisted.web.iweb import IBodyProducer
|
||||
from zope.interface import implements
|
||||
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.server.sessionhandler import SESSIONS
|
||||
from evennia.utils import get_evennia_version, logger
|
||||
|
||||
|
|
@ -97,8 +97,8 @@ class EvenniaGameIndexClient(object):
|
|||
'web_client_url': egi_config.get('web_client_url') or '',
|
||||
|
||||
# Game stats
|
||||
'connected_player_count': SESSIONS.player_count(),
|
||||
'total_player_count': PlayerDB.objects.num_total_players() or 0,
|
||||
'connected_account_count': SESSIONS.account_count(),
|
||||
'total_account_count': AccountDB.objects.num_total_accounts() or 0,
|
||||
|
||||
# System info
|
||||
'evennia_version': get_evennia_version(),
|
||||
|
|
|
|||
|
|
@ -31,13 +31,12 @@ the module given by settings.CONNECTION_SCREEN_MODULE.
|
|||
"""
|
||||
import re
|
||||
from django.conf import settings
|
||||
from evennia.players.models import PlayerDB
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.server.models import ServerConfig
|
||||
from evennia.comms.models import ChannelDB
|
||||
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.utils import create, logger, utils, ansi
|
||||
from evennia.utils import logger, utils, ansi
|
||||
from evennia.commands.default.muxcommand import MuxCommand
|
||||
from evennia.commands.cmdhandler import CMD_LOGINSTART
|
||||
from evennia.commands.default import unloggedin as default_unloggedin # Used in CmdUnconnectedCreate
|
||||
|
|
@ -78,7 +77,7 @@ class CmdUnconnectedConnect(MuxCommand):
|
|||
have a unique position in that their `func()` receives
|
||||
a session object instead of a `source_object` like all
|
||||
other types of logged-in commands (this is because
|
||||
there is no object yet before the player has logged in)
|
||||
there is no object yet before the account has logged in)
|
||||
"""
|
||||
|
||||
session = self.caller
|
||||
|
|
@ -91,23 +90,22 @@ class CmdUnconnectedConnect(MuxCommand):
|
|||
password = arglist[1]
|
||||
|
||||
# Match an email address to an account.
|
||||
player = PlayerDB.objects.get_player_from_email(email)
|
||||
# No playername match
|
||||
if not player:
|
||||
account = AccountDB.objects.get_account_from_email(email)
|
||||
# No accountname match
|
||||
if not account:
|
||||
string = "The email '%s' does not match any accounts." % email
|
||||
string += "\n\r\n\rIf you are new you should first create a new account "
|
||||
string += "using the 'create' command."
|
||||
session.msg(string)
|
||||
return
|
||||
# We have at least one result, so we can check the password.
|
||||
if not player.check_password(password):
|
||||
if not account[0].check_password(password):
|
||||
session.msg("Incorrect password.")
|
||||
return
|
||||
|
||||
# Check IP and/or name bans
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
if bans and (any(tup[0] == player.name for tup in bans)
|
||||
or
|
||||
if bans and (any(tup[0] == account.name for tup in bans) or
|
||||
any(tup[2].match(session.address[0]) for tup in bans if tup[2])):
|
||||
# this is a banned IP or name!
|
||||
string = "|rYou have been banned and cannot continue from here."
|
||||
|
|
@ -117,7 +115,7 @@ class CmdUnconnectedConnect(MuxCommand):
|
|||
return
|
||||
|
||||
# actually do the login. This will call all hooks.
|
||||
session.sessionhandler.login(session, player)
|
||||
session.sessionhandler.login(session, account)
|
||||
|
||||
|
||||
class CmdUnconnectedCreate(MuxCommand):
|
||||
|
|
@ -125,9 +123,9 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
Create a new account.
|
||||
|
||||
Usage (at login screen):
|
||||
create \"playername\" <email> <password>
|
||||
create \"accountname\" <email> <password>
|
||||
|
||||
This creates a new player account.
|
||||
This creates a new account account.
|
||||
|
||||
"""
|
||||
key = "create"
|
||||
|
|
@ -136,36 +134,36 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
|
||||
def parse(self):
|
||||
"""
|
||||
The parser must handle the multiple-word player
|
||||
The parser must handle the multiple-word account
|
||||
name enclosed in quotes:
|
||||
connect "Long name with many words" my@myserv.com mypassw
|
||||
"""
|
||||
super(CmdUnconnectedCreate, self).parse()
|
||||
|
||||
self.playerinfo = []
|
||||
self.accountinfo = []
|
||||
if len(self.arglist) < 3:
|
||||
return
|
||||
if len(self.arglist) > 3:
|
||||
# this means we have a multi_word playername. pop from the back.
|
||||
# this means we have a multi_word accountname. pop from the back.
|
||||
password = self.arglist.pop()
|
||||
email = self.arglist.pop()
|
||||
# what remains is the playername.
|
||||
playername = " ".join(self.arglist)
|
||||
# what remains is the accountname.
|
||||
accountname = " ".join(self.arglist)
|
||||
else:
|
||||
playername, email, password = self.arglist
|
||||
accountname, email, password = self.arglist
|
||||
|
||||
playername = playername.replace('"', '') # remove "
|
||||
playername = playername.replace("'", "")
|
||||
self.playerinfo = (playername, email, password)
|
||||
accountname = accountname.replace('"', '') # remove "
|
||||
accountname = accountname.replace("'", "")
|
||||
self.accountinfo = (accountname, email, password)
|
||||
|
||||
def func(self):
|
||||
"""Do checks and create account"""
|
||||
|
||||
session = self.caller
|
||||
try:
|
||||
playername, email, password = self.playerinfo
|
||||
accountname, email, password = self.accountinfo
|
||||
except ValueError:
|
||||
string = "\n\r Usage (without <>): create \"<playername>\" <email> <password>"
|
||||
string = "\n\r Usage (without <>): create \"<accountname>\" <email> <password>"
|
||||
session.msg(string)
|
||||
return
|
||||
if not email or not password:
|
||||
|
|
@ -176,26 +174,26 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
session.msg("'%s' is not a valid e-mail address." % email)
|
||||
return
|
||||
# sanity checks
|
||||
if not re.findall(r"^[\w. @+\-']+$", playername) or not (0 < len(playername) <= 30):
|
||||
if not re.findall(r"^[\w. @+\-']+$", accountname) or not (0 < len(accountname) <= 30):
|
||||
# this echoes the restrictions made by django's auth
|
||||
# module (except not allowing spaces, for convenience of
|
||||
# logging in).
|
||||
string = "\n\r Playername can max be 30 characters or fewer. Letters, spaces, digits and @/./+/-/_/' only."
|
||||
string = "\n\r Accountname can max be 30 characters or fewer. Letters, spaces, digits and @/./+/-/_/' only."
|
||||
session.msg(string)
|
||||
return
|
||||
# strip excessive spaces in playername
|
||||
playername = re.sub(r"\s+", " ", playername).strip()
|
||||
if PlayerDB.objects.filter(username__iexact=playername):
|
||||
# player already exists (we also ignore capitalization here)
|
||||
session.msg("Sorry, there is already a player with the name '%s'." % playername)
|
||||
# strip excessive spaces in accountname
|
||||
accountname = re.sub(r"\s+", " ", accountname).strip()
|
||||
if AccountDB.objects.filter(username__iexact=accountname):
|
||||
# account already exists (we also ignore capitalization here)
|
||||
session.msg("Sorry, there is already an account with the name '%s'." % accountname)
|
||||
return
|
||||
if PlayerDB.objects.get_player_from_email(email):
|
||||
# email already set on a player
|
||||
session.msg("Sorry, there is already a player with that email address.")
|
||||
if AccountDB.objects.get_account_from_email(email):
|
||||
# email already set on an account
|
||||
session.msg("Sorry, there is already an account with that email address.")
|
||||
return
|
||||
# Reserve playernames found in GUEST_LIST
|
||||
if settings.GUEST_LIST and playername.lower() in (guest.lower() for guest in settings.GUEST_LIST):
|
||||
string = "\n\r That name is reserved. Please choose another Playername."
|
||||
# Reserve accountnames found in GUEST_LIST
|
||||
if settings.GUEST_LIST and accountname.lower() in (guest.lower() for guest in settings.GUEST_LIST):
|
||||
string = "\n\r That name is reserved. Please choose another Accountname."
|
||||
session.msg(string)
|
||||
return
|
||||
if not re.findall(r"^[\w. @+\-']+$", password) or not (3 < len(password)):
|
||||
|
|
@ -207,8 +205,7 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
|
||||
# Check IP and/or name bans
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
if bans and (any(tup[0] == playername.lower() for tup in bans)
|
||||
or
|
||||
if bans and (any(tup[0] == accountname.lower() for tup in bans) or
|
||||
any(tup[2].match(session.address) for tup in bans if tup[2])):
|
||||
# this is a banned IP or name!
|
||||
string = "|rYou have been banned and cannot continue from here." \
|
||||
|
|
@ -219,20 +216,20 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
|
||||
# everything's ok. Create the new player account.
|
||||
try:
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
new_player = default_unloggedin._create_player(session, playername, password, permissions, email=email)
|
||||
if new_player:
|
||||
new_account = default_unloggedin._create_account(session, accountname, password, permissions, email=email)
|
||||
if new_account:
|
||||
if MULTISESSION_MODE < 2:
|
||||
default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
|
||||
default_unloggedin._create_character(session, new_player, typeclass, default_home, permissions)
|
||||
default_unloggedin._create_character(session, new_account, typeclass, default_home, permissions)
|
||||
# tell the caller everything went well.
|
||||
string = "A new account '%s' was created. Welcome!"
|
||||
if " " in playername:
|
||||
if " " in accountname:
|
||||
string += "\n\nYou can now log in with the command 'connect \"%s\" <your password>'."
|
||||
else:
|
||||
string += "\n\nYou can now log with the command 'connect %s <your password>'."
|
||||
session.msg(string % (playername, email))
|
||||
session.msg(string % (accountname, email))
|
||||
|
||||
except Exception:
|
||||
# We are in the middle between logged in and -not, so we have
|
||||
|
|
@ -246,7 +243,7 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
class CmdUnconnectedQuit(MuxCommand):
|
||||
"""
|
||||
We maintain a different version of the `quit` command
|
||||
here for unconnected players for the sake of simplicity. The logged in
|
||||
here for unconnected accounts for the sake of simplicity. The logged in
|
||||
version is a bit more complicated.
|
||||
"""
|
||||
key = "quit"
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ class CmdExtendedLook(default_cmds.CmdLook):
|
|||
look
|
||||
look <obj>
|
||||
look <room detail>
|
||||
look *<player>
|
||||
look *<account>
|
||||
|
||||
Observes your location, details at your location or objects in your vicinity.
|
||||
"""
|
||||
|
|
@ -315,7 +315,7 @@ class CmdExtendedLook(default_cmds.CmdLook):
|
|||
return
|
||||
|
||||
if not hasattr(looking_at_obj, 'return_appearance'):
|
||||
# this is likely due to us having a player instead
|
||||
# this is likely due to us having an account instead
|
||||
looking_at_obj = looking_at_obj.character
|
||||
if not looking_at_obj.access(caller, "view"):
|
||||
caller.msg("Could not find '%s'." % args)
|
||||
|
|
@ -377,7 +377,7 @@ class CmdExtendedDesc(default_cmds.CmdDesc):
|
|||
"""Define extended command"""
|
||||
caller = self.caller
|
||||
location = caller.location
|
||||
if self.cmdstring == '@detail':
|
||||
if self.cmdname == 'detail':
|
||||
# switch to detailing mode. This operates only on current location
|
||||
if not location:
|
||||
caller.msg("No location to detail!")
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class CallbackHandler(object):
|
|||
Args:
|
||||
callback_name (str): the name of the callback to add.
|
||||
code (str): the Python code associated with this callback.
|
||||
author (Character or Player, optional): the author of the callback.
|
||||
author (Character or Account, optional): the author of the callback.
|
||||
valid (bool, optional): should the callback be connected?
|
||||
parameters (str, optional): optional parameters.
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ class CallbackHandler(object):
|
|||
callback_name (str): the name of the callback to edit.
|
||||
number (int): the callback number to be changed.
|
||||
code (str): the Python code associated with this callback.
|
||||
author (Character or Player, optional): the author of the callback.
|
||||
author (Character or Account, optional): the author of the callback.
|
||||
valid (bool, optional): should the callback be connected?
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
|||
# Permissions
|
||||
WITH_VALIDATION = getattr(settings, "callbackS_WITH_VALIDATION", None)
|
||||
WITHOUT_VALIDATION = getattr(settings, "callbackS_WITHOUT_VALIDATION",
|
||||
"immortals")
|
||||
VALIDATING = getattr(settings, "callbackS_VALIDATING", "immortals")
|
||||
"developer")
|
||||
VALIDATING = getattr(settings, "callbackS_VALIDATING", "developer")
|
||||
|
||||
# Split help text
|
||||
BASIC_HELP = "Add, edit or delete callbacks."
|
||||
|
|
@ -94,7 +94,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
|
|||
on user permission.
|
||||
|
||||
Args:
|
||||
caller (Object or Player): the caller asking for help on the command.
|
||||
caller (Object or Account): the caller asking for help on the command.
|
||||
cmdset (CmdSet): the command set (if you need additional commands).
|
||||
|
||||
Returns:
|
||||
|
|
@ -360,8 +360,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
|
|||
callback = dict(callback)
|
||||
self.caller.db._callback = callback
|
||||
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
|
||||
quitfunc=_ev_quit, key="Callback {} of {}".format(
|
||||
callback_name, obj), persistent=True, codefunc=_ev_save)
|
||||
quitfunc=_ev_quit, key="Callback {} of {}".format(
|
||||
callback_name, obj), persistent=True, codefunc=_ev_save)
|
||||
|
||||
def del_callback(self):
|
||||
"""Delete a callback."""
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ class EventHandler(DefaultScript):
|
|||
obj (Object): the Evennia typeclassed object to be extended.
|
||||
callback_name (str): the name of the callback to add.
|
||||
code (str): the Python code associated with this callback.
|
||||
author (Character or Player, optional): the author of the callback.
|
||||
author (Character or Account, optional): the author of the callback.
|
||||
valid (bool, optional): should the callback be connected?
|
||||
parameters (str, optional): optional parameters.
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ class EventHandler(DefaultScript):
|
|||
callback_name (str): the name of the callback to edit.
|
||||
number (int): the callback number to be changed.
|
||||
code (str): the Python code associated with this callback.
|
||||
author (Character or Player, optional): the author of the callback.
|
||||
author (Character or Account, optional): the author of the callback.
|
||||
valid (bool, optional): should the callback be connected?
|
||||
|
||||
Raises:
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ This event is called when another character arrives in the location
|
|||
where the current character is. For instance, a puppeted character
|
||||
arrives in the shop of a shopkeeper (assuming the shopkeeper is
|
||||
a character). As its name suggests, this event can be very useful
|
||||
to have NPC greeting one another, or players, who come to visit.
|
||||
to have NPC greeting one another, or accounts, who come to visit.
|
||||
|
||||
Variables you can use in this event:
|
||||
character: the character connected to this event.
|
||||
|
|
@ -100,9 +100,9 @@ Variables you can use in this event:
|
|||
"""
|
||||
|
||||
CHARACTER_PUPPETED = """
|
||||
When the character has been puppeted by a player.
|
||||
This event is called when a player has just puppeted this character.
|
||||
This can commonly happen when a player connects onto this character,
|
||||
When the character has been puppeted by an account.
|
||||
This event is called when an account has just puppeted this character.
|
||||
This can commonly happen when an account connects onto this character,
|
||||
or when puppeting to a NPC or free character.
|
||||
|
||||
Variables you can use in this event:
|
||||
|
|
@ -151,8 +151,8 @@ Variables you can use in this event:
|
|||
|
||||
CHARACTER_UNPUPPETED = """
|
||||
When the character is about to be un-puppeted.
|
||||
This event is called when a player is about to un-puppet the
|
||||
character, which can happen if the player is disconnecting or
|
||||
This event is called when an account is about to un-puppet the
|
||||
character, which can happen if the account is disconnecting or
|
||||
changing puppets.
|
||||
|
||||
Variables you can use in this event:
|
||||
|
|
@ -244,8 +244,8 @@ class EventCharacter(DefaultCharacter):
|
|||
|
||||
"""
|
||||
|
||||
if not source_location and self.location.has_player:
|
||||
# This was created from nowhere and added to a player's
|
||||
if not source_location and self.location.has_account:
|
||||
# This was created from nowhere and added to an account's
|
||||
# inventory; it's probably the result of a create command.
|
||||
string = "You now have %s in your possession." % self.get_display_name(self.location)
|
||||
self.location.msg(string)
|
||||
|
|
@ -357,11 +357,11 @@ class EventCharacter(DefaultCharacter):
|
|||
def at_post_puppet(self):
|
||||
"""
|
||||
Called just after puppeting has been completed and all
|
||||
Player<->Object links have been established.
|
||||
Account<->Object links have been established.
|
||||
|
||||
Note:
|
||||
You can use `self.player` and `self.sessions.get()` to get
|
||||
player and sessions at this point; the last entry in the
|
||||
You can use `self.account` and `self.sessions.get()` to get
|
||||
account and sessions at this point; the last entry in the
|
||||
list from `self.sessions.get()` is the latest Session
|
||||
puppeting this Object.
|
||||
|
||||
|
|
@ -378,11 +378,11 @@ class EventCharacter(DefaultCharacter):
|
|||
def at_pre_unpuppet(self):
|
||||
"""
|
||||
Called just before beginning to un-connect a puppeting from
|
||||
this Player.
|
||||
this Account.
|
||||
|
||||
Note:
|
||||
You can use `self.player` and `self.sessions.get()` to get
|
||||
player and sessions at this point; the last entry in the
|
||||
You can use `self.account` and `self.sessions.get()` to get
|
||||
account and sessions at this point; the last entry in the
|
||||
list from `self.sessions.get()` is the latest Session
|
||||
puppeting this Object.
|
||||
|
||||
|
|
@ -683,7 +683,7 @@ Variables you can use in this event:
|
|||
ROOM_PUPPETED_IN = """
|
||||
After the character has been puppeted in this room.
|
||||
This event is called after a character has been puppeted in this
|
||||
room. This can happen when a player, having connected, begins
|
||||
room. This can happen when an account, having connected, begins
|
||||
to puppet a character. The character's location at this point,
|
||||
if it's a room, will see this event fire.
|
||||
|
||||
|
|
@ -733,7 +733,7 @@ Variables you can use in this event:
|
|||
ROOM_UNPUPPETED_IN = """
|
||||
Before the character is un-puppeted in this room.
|
||||
This event is called before a character is un-puppeted in this
|
||||
room. This can happen when a player, puppeting a character, is
|
||||
room. This can happen when an account, puppeting a character, is
|
||||
disconnecting. The character's location at this point, if it's a
|
||||
room, will see this event fire.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ A simple Brandymail style @mail system that uses the Msg class from Evennia Core
|
|||
|
||||
Installation:
|
||||
import CmdMail from this module (from evennia.contrib.mail import CmdMail),
|
||||
and add into the default Player or Character command set (self.add(CmdMail)).
|
||||
and add into the default Account or Character command set (self.add(CmdMail)).
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
from evennia import ObjectDB, PlayerDB
|
||||
from evennia import ObjectDB, AccountDB
|
||||
from evennia import default_cmds
|
||||
from evennia.utils import create, evtable, make_iter
|
||||
from evennia.comms.models import Msg
|
||||
|
|
@ -27,17 +27,17 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
Commands that allow either IC or OOC communications
|
||||
|
||||
Usage:
|
||||
@mail - Displays all the mail a player has in their mailbox
|
||||
@mail - Displays all the mail an account has in their mailbox
|
||||
|
||||
@mail <#> - Displays a specific message
|
||||
|
||||
@mail <players>=<subject>/<message>
|
||||
- Sends a message to the comma separated list of players.
|
||||
@mail <accounts>=<subject>/<message>
|
||||
- Sends a message to the comma separated list of accounts.
|
||||
|
||||
@mail/delete <#> - Deletes a specific message
|
||||
|
||||
@mail/forward <player list>=<#>[/<Message>]
|
||||
- Forwards an existing message to the specified list of players,
|
||||
@mail/forward <account list>=<#>[/<Message>]
|
||||
- Forwards an existing message to the specified list of accounts,
|
||||
original message is delivered with optional Message prepended.
|
||||
|
||||
@mail/reply <#>=<message>
|
||||
|
|
@ -65,7 +65,7 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
Search a list of targets of the same type as caller.
|
||||
|
||||
Args:
|
||||
caller (Object or Player): The type of object to search.
|
||||
caller (Object or Account): The type of object to search.
|
||||
namelist (list): List of strings for objects to search for.
|
||||
|
||||
Returns:
|
||||
|
|
@ -73,10 +73,10 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
|
||||
"""
|
||||
nameregex = r"|".join(r"^%s$" % re.escape(name) for name in make_iter(namelist))
|
||||
if hasattr(self.caller, "player") and self.caller.player:
|
||||
if hasattr(self.caller, "account") and self.caller.account:
|
||||
matches = list(ObjectDB.objects.filter(db_key__iregex=nameregex))
|
||||
else:
|
||||
matches = list(PlayerDB.objects.filter(username__iregex=nameregex))
|
||||
matches = list(AccountDB.objects.filter(username__iregex=nameregex))
|
||||
return matches
|
||||
|
||||
def get_all_mail(self):
|
||||
|
|
@ -89,10 +89,10 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
# mail_messages = Msg.objects.get_by_tag(category="mail")
|
||||
# messages = []
|
||||
try:
|
||||
player = self.caller.player
|
||||
account = self.caller.account
|
||||
except AttributeError:
|
||||
player = self.caller
|
||||
messages = Msg.objects.get_by_tag(category="mail", raw_queryset=True).filter(db_receivers_players=player)
|
||||
account = self.caller
|
||||
messages = Msg.objects.get_by_tag(category="mail").filter(db_receivers_accounts=account)
|
||||
return messages
|
||||
|
||||
def send_mail(self, recipients, subject, message, caller):
|
||||
|
|
@ -100,10 +100,10 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
Function for sending new mail. Also useful for sending notifications from objects or systems.
|
||||
|
||||
Args:
|
||||
recipients (list): list of Player or character objects to receive the newly created mails.
|
||||
recipients (list): list of Account or character objects to receive the newly created mails.
|
||||
subject (str): The header or subject of the message to be delivered.
|
||||
message (str): The body of the message being sent.
|
||||
caller (obj): The object (or Player or Character) that is sending the message.
|
||||
caller (obj): The object (or Account or Character) that is sending the message.
|
||||
"""
|
||||
for recipient in recipients:
|
||||
recipient.msg("You have received a new @mail from %s" % caller)
|
||||
|
|
@ -114,7 +114,7 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
caller.msg("You sent your message.")
|
||||
return
|
||||
else:
|
||||
caller.msg("No valid players found. Cannot send message.")
|
||||
caller.msg("No valid accounts found. Cannot send message.")
|
||||
return
|
||||
|
||||
def func(self):
|
||||
|
|
@ -142,7 +142,7 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
elif "forward" in self.switches:
|
||||
try:
|
||||
if not self.rhs:
|
||||
self.caller.msg("Cannot forward a message without a player list. Please try again.")
|
||||
self.caller.msg("Cannot forward a message without an account list. Please try again.")
|
||||
return
|
||||
elif not self.lhs:
|
||||
self.caller.msg("You must define a message to forward.")
|
||||
|
|
@ -176,7 +176,7 @@ class CmdMail(default_cmds.MuxCommand):
|
|||
except IndexError:
|
||||
self.caller.msg("Message does not exixt.")
|
||||
except ValueError:
|
||||
self.caller.msg("Usage: @mail/forward <player list>=<#>[/<Message>]")
|
||||
self.caller.msg("Usage: @mail/forward <account list>=<#>[/<Message>]")
|
||||
elif "reply" in self.switches:
|
||||
try:
|
||||
if not self.rhs:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ called and so on until the map is completed. Building instructions are passed
|
|||
the following arguments:
|
||||
x - The rooms position on the maps x axis
|
||||
y - The rooms position on the maps y axis
|
||||
caller - The player calling the command
|
||||
caller - The account calling the command
|
||||
iteration - The current iterations number (0, 1 or 2)
|
||||
room_dict - A dictionary containing room references returned by build
|
||||
functions where tuple coordinates are the keys (x, y).
|
||||
|
|
@ -119,7 +119,7 @@ def example1_build_forest(x, y, **kwargs):
|
|||
room = create_object(rooms.Room, key="forest" + str(x) + str(y))
|
||||
room.db.desc = "Basic forest room."
|
||||
|
||||
# Send a message to the player
|
||||
# Send a message to the account
|
||||
kwargs["caller"].msg(room.key + " " + room.dbref)
|
||||
|
||||
# This is generally mandatory.
|
||||
|
|
@ -143,7 +143,7 @@ def example1_build_mountains(x, y, **kwargs):
|
|||
rock = create_object(key="Rock", location=room)
|
||||
rock.db.desc = "An ordinary rock."
|
||||
|
||||
# Send a message to the player
|
||||
# Send a message to the account
|
||||
kwargs["caller"].msg(room.key + " " + room.dbref)
|
||||
|
||||
# This is generally mandatory.
|
||||
|
|
@ -167,7 +167,7 @@ def example1_build_temple(x, y, **kwargs):
|
|||
"keeping the sound level only just below thunderous. "
|
||||
"This is a rare spot of mirth on this dread moor.")
|
||||
|
||||
# Send a message to the player
|
||||
# Send a message to the account
|
||||
kwargs["caller"].msg(room.key + " " + room.dbref)
|
||||
|
||||
# This is generally mandatory.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ CMDSET_UNLOGGEDIN = "contrib.menu_login.UnloggedinCmdSet"
|
|||
When you'll reload the server, new sessions will connect to the new
|
||||
login system, where they will be able to:
|
||||
|
||||
* Enter their username, assuming they have an existing player.
|
||||
* Enter 'NEW' to create a new player.
|
||||
* Enter their username, assuming they have an existing account.
|
||||
* Enter 'NEW' to create a new account.
|
||||
|
||||
The top-level functions in this file are menu nodes (as described in
|
||||
evennia.utils.evmenu.py). Each one of these functions is responsible
|
||||
|
|
@ -61,7 +61,7 @@ def start(caller):
|
|||
a session has been created OR if an error occurs further
|
||||
down the menu tree. From there, users can either enter a
|
||||
username (if this username exists) or type NEW (capitalized
|
||||
or not) to create a new player.
|
||||
or not) to create a new account.
|
||||
|
||||
"""
|
||||
text = random_string_from_module(CONNECTION_SCREEN_MODULE)
|
||||
|
|
@ -79,7 +79,7 @@ def start(caller):
|
|||
|
||||
|
||||
def username(caller, string_input):
|
||||
"""Check that the username leads to an existing player.
|
||||
"""Check that the username leads to an existing account.
|
||||
|
||||
Check that the specified username exists. If the username doesn't
|
||||
exist, display an error message and ask the user to try again. If
|
||||
|
|
@ -88,8 +88,8 @@ def username(caller, string_input):
|
|||
|
||||
"""
|
||||
string_input = string_input.strip()
|
||||
player = managers.players.get_player_from_name(string_input)
|
||||
if player is None:
|
||||
account = managers.accounts.get_account_from_name(string_input)
|
||||
if account is None:
|
||||
text = dedent("""
|
||||
|rThe username '{}' doesn't exist. Have you created it?|n
|
||||
Try another name or leave empty to go back.
|
||||
|
|
@ -100,8 +100,8 @@ def username(caller, string_input):
|
|||
{"key": "_default",
|
||||
"goto": "username"})
|
||||
else:
|
||||
caller.ndb._menutree.player = player
|
||||
text = "Enter the password for the {} account.".format(player.name)
|
||||
caller.ndb._menutree.account = account
|
||||
text = "Enter the password for the {} account.".format(account.name)
|
||||
# Disables echo for the password
|
||||
caller.msg("", options={"echo": False})
|
||||
options = (
|
||||
|
|
@ -115,7 +115,7 @@ def username(caller, string_input):
|
|||
|
||||
|
||||
def ask_password(caller, string_input):
|
||||
"""Ask the user to enter the password to this player.
|
||||
"""Ask the user to enter the password to this account.
|
||||
|
||||
This is assuming the user exists (see 'create_username' and
|
||||
'create_password'). This node "loops" if needed: if the
|
||||
|
|
@ -129,14 +129,14 @@ def ask_password(caller, string_input):
|
|||
|
||||
# Check the password and login is correct; also check for bans
|
||||
|
||||
player = menutree.player
|
||||
account = menutree.account
|
||||
password_attempts = menutree.password_attempts \
|
||||
if hasattr(menutree, "password_attempts") else 0
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
banned = bans and (any(tup[0] == player.name.lower() for tup in bans) or
|
||||
banned = bans and (any(tup[0] == account.name.lower() for tup in bans) or
|
||||
any(tup[2].match(caller.address) for tup in bans if tup[2]))
|
||||
|
||||
if not player.check_password(string_input):
|
||||
if not account.check_password(string_input):
|
||||
# Didn't enter a correct password
|
||||
password_attempts += 1
|
||||
if password_attempts > 2:
|
||||
|
|
@ -173,7 +173,7 @@ def ask_password(caller, string_input):
|
|||
text = ""
|
||||
options = {}
|
||||
caller.msg("", options={"echo": True})
|
||||
caller.sessionhandler.login(caller, player)
|
||||
caller.sessionhandler.login(caller, account)
|
||||
|
||||
return text, options
|
||||
|
||||
|
|
@ -201,10 +201,10 @@ def create_username(caller, string_input):
|
|||
"""
|
||||
menutree = caller.ndb._menutree
|
||||
string_input = string_input.strip()
|
||||
player = managers.players.get_player_from_name(string_input)
|
||||
account = managers.accounts.get_account_from_name(string_input)
|
||||
|
||||
# If a player with that name exists, a new one will not be created
|
||||
if player:
|
||||
# If an account with that name exists, a new one will not be created
|
||||
if account:
|
||||
text = dedent("""
|
||||
|rThe account {} already exists.|n
|
||||
Enter another username or leave blank to go back.
|
||||
|
|
@ -229,7 +229,7 @@ def create_username(caller, string_input):
|
|||
"goto": "create_username"})
|
||||
else:
|
||||
# a valid username - continue getting the password
|
||||
menutree.playername = string_input
|
||||
menutree.accountname = string_input
|
||||
# Disables echo for entering password
|
||||
caller.msg("", options={"echo": False})
|
||||
# Redirects to the creation of a password
|
||||
|
|
@ -259,7 +259,7 @@ def create_password(caller, string_input):
|
|||
"goto": "create_password"})
|
||||
|
||||
password = string_input.strip()
|
||||
playername = menutree.playername
|
||||
accountname = menutree.accountname
|
||||
|
||||
if len(password) < LEN_PASSWD:
|
||||
# The password is too short
|
||||
|
|
@ -273,15 +273,15 @@ def create_password(caller, string_input):
|
|||
from evennia.commands.default import unloggedin
|
||||
# We make use of the helper functions from the default set here.
|
||||
try:
|
||||
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
|
||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
new_player = unloggedin._create_player(caller, playername,
|
||||
new_account = unloggedin._create_account(caller, accountname,
|
||||
password, permissions)
|
||||
if new_player:
|
||||
if new_account:
|
||||
if settings.MULTISESSION_MODE < 2:
|
||||
default_home = ObjectDB.objects.get_id(
|
||||
settings.DEFAULT_HOME)
|
||||
unloggedin._create_character(caller, new_player,
|
||||
unloggedin._create_character(caller, new_account,
|
||||
typeclass, default_home, permissions)
|
||||
except Exception:
|
||||
# We are in the middle between logged in and -not, so we have
|
||||
|
|
@ -297,7 +297,7 @@ def create_password(caller, string_input):
|
|||
text = ""
|
||||
caller.msg("|gWelcome, your new account has been created!|n")
|
||||
caller.msg("", options={"echo": True})
|
||||
caller.sessionhandler.login(caller, new_player)
|
||||
caller.sessionhandler.login(caller, new_account)
|
||||
|
||||
return text, options
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ class UnloggedinCmdSet(CmdSet):
|
|||
class CmdUnloggedinLook(Command):
|
||||
"""
|
||||
An unloggedin version of the look command. This is called by the server
|
||||
when the player first connects. It sets up the menu before handing off
|
||||
when the account first connects. It sets up the menu before handing off
|
||||
to the menu's own look command.
|
||||
"""
|
||||
key = syscmdkeys.CMD_LOGINSTART
|
||||
|
|
|
|||
|
|
@ -1203,14 +1203,14 @@ class ContribRPObject(DefaultObject):
|
|||
nofound_string (str): optional custom string for not-found error message.
|
||||
multimatch_string (str): optional custom string for multimatch error header.
|
||||
use_dbref (bool or None): If None, only turn off use_dbref if we are of a lower
|
||||
permission than Builders. Otherwise, honor the True/False value.
|
||||
permission than Builder. Otherwise, honor the True/False value.
|
||||
|
||||
Returns:
|
||||
match (Object, None or list): will return an Object/None if `quiet=False`,
|
||||
otherwise it will return a list of 0, 1 or more matches.
|
||||
|
||||
Notes:
|
||||
To find Players, use eg. `evennia.player_search`. If
|
||||
To find Accounts, use eg. `evennia.account_search`. If
|
||||
`quiet=False`, error messages will be handled by
|
||||
`settings.SEARCH_AT_RESULT` and echoed automatically (on
|
||||
error, return will be `None`). If `quiet=True`, the error
|
||||
|
|
@ -1228,7 +1228,7 @@ class ContribRPObject(DefaultObject):
|
|||
|
||||
if use_nicks:
|
||||
# do nick-replacement on search
|
||||
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "player"), include_player=True)
|
||||
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "account"), include_account=True)
|
||||
|
||||
if(global_search or (is_string and searchdata.startswith("#") and
|
||||
len(searchdata) > 1 and searchdata[1:].isdigit())):
|
||||
|
|
@ -1256,7 +1256,7 @@ class ContribRPObject(DefaultObject):
|
|||
candidates.append(self)
|
||||
|
||||
# the sdesc-related substitution
|
||||
is_builder = self.locks.check_lockstring(self, "perm(Builders)")
|
||||
is_builder = self.locks.check_lockstring(self, "perm(Builder)")
|
||||
use_dbref = is_builder if use_dbref is None else use_dbref
|
||||
search_obj = lambda string: ObjectDB.objects.object_search(string,
|
||||
attribute_name=attribute_name,
|
||||
|
|
@ -1296,7 +1296,7 @@ class ContribRPObject(DefaultObject):
|
|||
Displays the name of the object in a viewer-aware manner.
|
||||
|
||||
Args:
|
||||
looker (TypedObject): The object or player that is looking
|
||||
looker (TypedObject): The object or account that is looking
|
||||
at/getting inforamtion for this object.
|
||||
|
||||
Kwargs:
|
||||
|
|
@ -1342,7 +1342,7 @@ class ContribRPObject(DefaultObject):
|
|||
key = con.get_display_name(looker, pose=True)
|
||||
if con.destination:
|
||||
exits.append(key)
|
||||
elif con.has_player:
|
||||
elif con.has_account:
|
||||
users.append(key)
|
||||
else:
|
||||
things.append(key)
|
||||
|
|
@ -1383,7 +1383,7 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
|||
Displays the name of the object in a viewer-aware manner.
|
||||
|
||||
Args:
|
||||
looker (TypedObject): The object or player that is looking
|
||||
looker (TypedObject): The object or account that is looking
|
||||
at/getting inforamtion for this object.
|
||||
|
||||
Kwargs:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ Testing suite for contrib folder
|
|||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
from django.test import override_settings
|
||||
from evennia.commands.default.tests import CommandTest
|
||||
from evennia.utils.test_resources import EvenniaTest
|
||||
from mock import Mock, patch
|
||||
|
|
@ -219,13 +221,12 @@ class TestExtendedRoom(CommandTest):
|
|||
self.call(extended_room.CmdExtendedLook(), "nonexistent", "Could not find 'nonexistent'.")
|
||||
|
||||
def test_cmdextendeddesc(self):
|
||||
self.call(extended_room.CmdExtendedDesc(), "", "Details on Room", cmdstring="@detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "", "Details on Room", cmdstring="detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "thingie = newdetail with spaces",
|
||||
"Set Detail thingie to 'newdetail with spaces'.", cmdstring="@detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' on Room:\n", cmdstring="@detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "/del thingie",
|
||||
"Detail thingie deleted, if it existed.", cmdstring="@detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' not found.", cmdstring="@detail")
|
||||
"Set Detail thingie to 'newdetail with spaces'.", cmdstring="detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' on Room:\n", cmdstring="detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "/del thingie", "Detail thingie deleted, if it existed.", cmdstring="detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' not found.", cmdstring="detail")
|
||||
self.call(extended_room.CmdExtendedDesc(), "", "Descriptions on Room:")
|
||||
|
||||
def test_cmdgametime(self):
|
||||
|
|
@ -396,13 +397,13 @@ class TestWilderness(EvenniaTest):
|
|||
# Pretend that both char1 and char2 are connected...
|
||||
self.char1.sessions.add(1)
|
||||
self.char2.sessions.add(1)
|
||||
self.assertTrue(self.char1.has_player)
|
||||
self.assertTrue(self.char2.has_player)
|
||||
self.assertTrue(self.char1.has_account)
|
||||
self.assertTrue(self.char2.has_account)
|
||||
|
||||
wilderness.create_wilderness()
|
||||
w = self.get_wilderness_script()
|
||||
|
||||
# We should have no unused room after moving the first player in.
|
||||
# We should have no unused room after moving the first account in.
|
||||
self.assertEquals(len(w.db.unused_rooms), 0)
|
||||
w.move_obj(self.char1, (0, 0))
|
||||
self.assertEquals(len(w.db.unused_rooms), 0)
|
||||
|
|
@ -443,15 +444,15 @@ from evennia.contrib import chargen
|
|||
class TestChargen(CommandTest):
|
||||
|
||||
def test_ooclook(self):
|
||||
self.call(chargen.CmdOOCLook(), "foo", "You have no characters to look at", caller=self.player)
|
||||
self.call(chargen.CmdOOCLook(), "", "You, TestPlayer, are an OOC ghost without form.", caller=self.player)
|
||||
self.call(chargen.CmdOOCLook(), "foo", "You have no characters to look at", caller=self.account)
|
||||
self.call(chargen.CmdOOCLook(), "", "You, TestAccount, are an OOC ghost without form.", caller=self.account)
|
||||
|
||||
def test_charcreate(self):
|
||||
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "The character testchar was successfully created!", caller=self.player)
|
||||
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "Character testchar already exists.", caller=self.player)
|
||||
self.assertTrue(self.player.db._character_dbrefs)
|
||||
self.call(chargen.CmdOOCLook(), "", "You, TestPlayer, are an OOC ghost without form.",caller=self.player)
|
||||
self.call(chargen.CmdOOCLook(), "testchar", "testchar(", caller=self.player)
|
||||
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "The character testchar was successfully created!", caller=self.account)
|
||||
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "Character testchar already exists.", caller=self.account)
|
||||
self.assertTrue(self.account.db._character_dbrefs)
|
||||
self.call(chargen.CmdOOCLook(), "", "You, TestAccount, are an OOC ghost without form.",caller=self.account)
|
||||
self.call(chargen.CmdOOCLook(), "testchar", "testchar(", caller=self.account)
|
||||
|
||||
# Testing clothing contrib
|
||||
from evennia.contrib import clothing
|
||||
|
|
@ -601,9 +602,9 @@ class TestEmailLogin(CommandTest):
|
|||
def test_connect(self):
|
||||
self.call(email_login.CmdUnconnectedConnect(), "mytest@test.com test", "The email 'mytest@test.com' does not match any accounts.")
|
||||
self.call(email_login.CmdUnconnectedCreate(), '"mytest" mytest@test.com test11111', "A new account 'mytest' was created. Welcome!")
|
||||
self.call(email_login.CmdUnconnectedConnect(), "mytest@test.com test11111", "", caller=self.player.sessions.get()[0])
|
||||
self.call(email_login.CmdUnconnectedConnect(), "mytest@test.com test11111", "", caller=self.account.sessions.get()[0])
|
||||
def test_quit(self):
|
||||
self.call(email_login.CmdUnconnectedQuit(), "", "", caller=self.player.sessions.get()[0])
|
||||
self.call(email_login.CmdUnconnectedQuit(), "", "", caller=self.account.sessions.get()[0])
|
||||
def test_unconnectedlook(self):
|
||||
self.call(email_login.CmdUnconnectedLook(), "", "==========")
|
||||
def test_unconnectedhelp(self):
|
||||
|
|
@ -629,19 +630,19 @@ from evennia.contrib import mail
|
|||
|
||||
class TestMail(CommandTest):
|
||||
def test_mail(self):
|
||||
self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.player)
|
||||
self.call(mail.CmdMail(), "", "There are no messages in your inbox.", caller=self.player)
|
||||
self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account)
|
||||
self.call(mail.CmdMail(), "", "There are no messages in your inbox.", caller=self.account)
|
||||
self.call(mail.CmdMail(), "Char=Message 1", "You have received a new @mail from Char|You sent your message.", caller=self.char1)
|
||||
self.call(mail.CmdMail(), "Char=Message 2", "You sent your message.", caller=self.char2)
|
||||
self.call(mail.CmdMail(), "TestPlayer2=Message 2",
|
||||
"You have received a new @mail from TestPlayer2(player 2)|You sent your message.", caller=self.player2)
|
||||
self.call(mail.CmdMail(), "TestPlayer=Message 1", "You sent your message.", caller=self.player2)
|
||||
self.call(mail.CmdMail(), "TestPlayer=Message 2", "You sent your message.", caller=self.player2)
|
||||
self.call(mail.CmdMail(), "", "| ID: From: Subject:", caller=self.player)
|
||||
self.call(mail.CmdMail(), "2", "From: TestPlayer2", caller=self.player)
|
||||
self.call(mail.CmdMail(), "/forward TestPlayer2 = 1/Forward message", "You sent your message.|Message forwarded.", caller=self.player)
|
||||
self.call(mail.CmdMail(), "/reply 2=Reply Message2", "You sent your message.", caller=self.player)
|
||||
self.call(mail.CmdMail(), "/delete 2", "Message 2 deleted", caller=self.player)
|
||||
self.call(mail.CmdMail(), "TestAccount2=Message 2",
|
||||
"You have received a new @mail from TestAccount2(account 2)|You sent your message.", caller=self.account2)
|
||||
self.call(mail.CmdMail(), "TestAccount=Message 1", "You sent your message.", caller=self.account2)
|
||||
self.call(mail.CmdMail(), "TestAccount=Message 2", "You sent your message.", caller=self.account2)
|
||||
self.call(mail.CmdMail(), "", "| ID: From: Subject:", caller=self.account)
|
||||
self.call(mail.CmdMail(), "2", "From: TestAccount2", caller=self.account)
|
||||
self.call(mail.CmdMail(), "/forward TestAccount2 = 1/Forward message", "You sent your message.|Message forwarded.", caller=self.account)
|
||||
self.call(mail.CmdMail(), "/reply 2=Reply Message2", "You sent your message.", caller=self.account)
|
||||
self.call(mail.CmdMail(), "/delete 2", "Message 2 deleted", caller=self.account)
|
||||
|
||||
# test map builder contrib
|
||||
|
||||
|
|
@ -985,3 +986,63 @@ class TestUnixCommand(CommandTest):
|
|||
lines = ret.splitlines()
|
||||
self.assertTrue(any(l.startswith("usage:") for l in lines))
|
||||
self.assertTrue(any(l.startswith("dummy: error:") for l in lines))
|
||||
|
||||
|
||||
import re
|
||||
from evennia.contrib import color_markups
|
||||
|
||||
class TestColorMarkup(EvenniaTest):
|
||||
"""
|
||||
Note: Normally this would be tested by importing the ansi parser and run
|
||||
the mappings through it. This is not possible since the ansi module creates
|
||||
its mapping at the module/class level; since the ansi module is used by so
|
||||
many other modules it appears that trying to overload
|
||||
settings to test it causes issues with unrelated tests.
|
||||
"""
|
||||
def test_curly_markup(self):
|
||||
ansi_map = color_markups.CURLY_COLOR_ANSI_EXTRA_MAP
|
||||
self.assertIsNotNone(re.match(re.escape(ansi_map[7][0]), '{r'))
|
||||
self.assertIsNotNone(re.match(re.escape(ansi_map[-1][0]), '{[X'))
|
||||
xterm_fg = color_markups.CURLY_COLOR_XTERM256_EXTRA_FG
|
||||
self.assertIsNotNone(re.match(xterm_fg[0], '{001'))
|
||||
self.assertIsNotNone(re.match(xterm_fg[0], '{123'))
|
||||
self.assertIsNotNone(re.match(xterm_fg[0], '{455'))
|
||||
xterm_bg = color_markups.CURLY_COLOR_XTERM256_EXTRA_BG
|
||||
self.assertIsNotNone(re.match(xterm_bg[0], '{[001'))
|
||||
self.assertIsNotNone(re.match(xterm_bg[0], '{[123'))
|
||||
self.assertIsNotNone(re.match(xterm_bg[0], '{[455'))
|
||||
xterm_gfg = color_markups.CURLY_COLOR_XTERM256_EXTRA_GFG
|
||||
self.assertIsNotNone(re.match(xterm_gfg[0], '{=h'))
|
||||
self.assertIsNotNone(re.match(xterm_gfg[0], '{=e'))
|
||||
self.assertIsNotNone(re.match(xterm_gfg[0], '{=w'))
|
||||
xterm_gbg = color_markups.CURLY_COLOR_XTERM256_EXTRA_GBG
|
||||
self.assertIsNotNone(re.match(xterm_gbg[0], '{[=a'))
|
||||
self.assertIsNotNone(re.match(xterm_gbg[0], '{[=k'))
|
||||
self.assertIsNotNone(re.match(xterm_gbg[0], '{[=z'))
|
||||
bright_map = color_markups.CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP
|
||||
self.assertEqual(bright_map[0][1], '{[500')
|
||||
self.assertEqual(bright_map[-1][1], '{[222')
|
||||
|
||||
def test_mux_markup(self):
|
||||
ansi_map = color_markups.MUX_COLOR_ANSI_EXTRA_MAP
|
||||
self.assertIsNotNone(re.match(re.escape(ansi_map[10][0]), '%cr'))
|
||||
self.assertIsNotNone(re.match(re.escape(ansi_map[-1][0]), '%cX'))
|
||||
xterm_fg = color_markups.MUX_COLOR_XTERM256_EXTRA_FG
|
||||
self.assertIsNotNone(re.match(xterm_fg[0], '%c001'))
|
||||
self.assertIsNotNone(re.match(xterm_fg[0], '%c123'))
|
||||
self.assertIsNotNone(re.match(xterm_fg[0], '%c455'))
|
||||
xterm_bg = color_markups.MUX_COLOR_XTERM256_EXTRA_BG
|
||||
self.assertIsNotNone(re.match(xterm_bg[0], '%c[001'))
|
||||
self.assertIsNotNone(re.match(xterm_bg[0], '%c[123'))
|
||||
self.assertIsNotNone(re.match(xterm_bg[0], '%c[455'))
|
||||
xterm_gfg = color_markups.MUX_COLOR_XTERM256_EXTRA_GFG
|
||||
self.assertIsNotNone(re.match(xterm_gfg[0], '%c=h'))
|
||||
self.assertIsNotNone(re.match(xterm_gfg[0], '%c=e'))
|
||||
self.assertIsNotNone(re.match(xterm_gfg[0], '%c=w'))
|
||||
xterm_gbg = color_markups.MUX_COLOR_XTERM256_EXTRA_GBG
|
||||
self.assertIsNotNone(re.match(xterm_gbg[0], '%c[=a'))
|
||||
self.assertIsNotNone(re.match(xterm_gbg[0], '%c[=k'))
|
||||
self.assertIsNotNone(re.match(xterm_gbg[0], '%c[=z'))
|
||||
bright_map = color_markups.MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP
|
||||
self.assertEqual(bright_map[0][1], '%c[500')
|
||||
self.assertEqual(bright_map[-1][1], '%c[222')
|
||||
|
|
|
|||
|
|
@ -297,17 +297,17 @@ class LidOpenCmdSet(CmdSet):
|
|||
|
||||
class BlindCmdSet(CmdSet):
|
||||
"""
|
||||
This is the cmdset added to the *player* when
|
||||
This is the cmdset added to the *account* when
|
||||
the button is pushed.
|
||||
"""
|
||||
key = "BlindCmdSet"
|
||||
# we want it to completely replace all normal commands
|
||||
# until the timed script removes it again.
|
||||
mergetype = "Replace"
|
||||
# we want to stop the player from walking around
|
||||
# we want to stop the account from walking around
|
||||
# in this blinded state, so we hide all exits too.
|
||||
# (channel commands will still work).
|
||||
no_exits = True # keep player in the same room
|
||||
no_exits = True # keep account in the same room
|
||||
no_objs = True # don't allow object commands
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
|
|
|
|||
|
|
@ -100,17 +100,17 @@ class BlindedState(DefaultScript):
|
|||
"""
|
||||
This is a timed state.
|
||||
|
||||
This adds a (very limited) cmdset TO THE PLAYER, during a certain time,
|
||||
This adds a (very limited) cmdset TO THE ACCOUNT, during a certain time,
|
||||
after which the script will close and all functions are
|
||||
restored. It's up to the function starting the script to actually
|
||||
set it on the right player object.
|
||||
set it on the right account object.
|
||||
"""
|
||||
def at_script_creation(self):
|
||||
"""
|
||||
We set up the script here.
|
||||
"""
|
||||
self.key = "temporary_blinder"
|
||||
self.desc = "Temporarily blinds the player for a little while."
|
||||
self.desc = "Temporarily blinds the account for a little while."
|
||||
self.interval = 20 # seconds
|
||||
self.start_delay = True # we don't want it to stop until after 20s.
|
||||
self.repeats = 1 # this will go away after interval seconds.
|
||||
|
|
@ -123,7 +123,7 @@ class BlindedState(DefaultScript):
|
|||
Note that the RedButtonBlind cmdset is defined to completly
|
||||
replace the other cmdsets on the stack while it is active
|
||||
(this means that while blinded, only operations in this cmdset
|
||||
will be possible for the player to perform). It is however
|
||||
will be possible for the account to perform). It is however
|
||||
not persistent, so should there be a bug in it, we just need
|
||||
to restart the server to clear out of it during development.
|
||||
"""
|
||||
|
|
@ -228,7 +228,7 @@ class DeactivateButtonEvent(DefaultScript):
|
|||
This deactivates the button for a short while (it won't blink, won't
|
||||
close its lid etc). It is meant to be called when the button is pushed
|
||||
and run as long as the blinded effect lasts. We cannot put these methods
|
||||
in the AddBlindedCmdSet script since that script is defined on the *player*
|
||||
in the AddBlindedCmdSet script since that script is defined on the *account*
|
||||
whereas this one must be defined on the *button*.
|
||||
"""
|
||||
def at_script_creation(self):
|
||||
|
|
@ -250,7 +250,7 @@ class DeactivateButtonEvent(DefaultScript):
|
|||
"""
|
||||
# closing the lid will also add the ClosedState script
|
||||
self.obj.close_lid()
|
||||
# lock the lid so other players can't access it until the
|
||||
# lock the lid so other accounts can't access it until the
|
||||
# first one's effect has worn off.
|
||||
self.obj.db.lid_locked = True
|
||||
# breaking the lamp also sets a correct desc
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ class Mob(tut_objects.TutorialObject):
|
|||
|
||||
"""
|
||||
targets = [obj for obj in location.contents_get(exclude=self)
|
||||
if obj.has_player and not obj.is_superuser]
|
||||
if obj.has_account and not obj.is_superuser]
|
||||
return targets[0] if targets else None
|
||||
|
||||
def set_alive(self, *args, **kwargs):
|
||||
|
|
@ -290,9 +290,9 @@ class Mob(tut_objects.TutorialObject):
|
|||
"""
|
||||
Called repeatedly during patrolling mode. In this mode, the
|
||||
mob scans its surroundings and randomly chooses a viable exit.
|
||||
One should lock exits with the traverse:has_player() lock in
|
||||
One should lock exits with the traverse:has_account() lock in
|
||||
order to block the mob from moving outside its area while
|
||||
allowing player-controlled characters to move normally.
|
||||
allowing account-controlled characters to move normally.
|
||||
"""
|
||||
if random.random() < 0.01 and self.db.irregular_msgs:
|
||||
self.location.msg_contents(random.choice(self.db.irregular_msgs))
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@ class CrumblingWall(TutorialObject, DefaultExit):
|
|||
The CrumblingWall can be examined in various ways, but only if a
|
||||
lit light source is in the room. The traversal itself is blocked
|
||||
by a traverse: lock on the exit that only allows passage if a
|
||||
certain attribute is set on the trying player.
|
||||
certain attribute is set on the trying account.
|
||||
|
||||
Important attribute
|
||||
destination - this property must be set to make this a valid exit
|
||||
|
|
@ -701,7 +701,7 @@ class CrumblingWall(TutorialObject, DefaultExit):
|
|||
self.reset()
|
||||
|
||||
def at_failed_traverse(self, traverser):
|
||||
"""This is called if the player fails to pass the Exit."""
|
||||
"""This is called if the account fails to pass the Exit."""
|
||||
traverser.msg("No matter how you try, you cannot force yourself through %s." % self.key)
|
||||
|
||||
def reset(self):
|
||||
|
|
@ -868,7 +868,7 @@ class Weapon(TutorialObject):
|
|||
When reset, the weapon is simply deleted, unless it has a place
|
||||
to return to.
|
||||
"""
|
||||
if self.location.has_player and self.home == self.location:
|
||||
if self.location.has_account and self.home == self.location:
|
||||
self.location.msg_contents("%s suddenly and magically fades into nothingness, as if it was never there ..."
|
||||
% self.key)
|
||||
self.delete()
|
||||
|
|
@ -1032,7 +1032,7 @@ class WeaponRack(TutorialObject):
|
|||
Attributes to set on this object:
|
||||
available_weapons: list of prototype-keys from
|
||||
WEAPON_PROTOTYPES, the weapons available in this rack.
|
||||
no_more_weapons_msg - error message to return to players
|
||||
no_more_weapons_msg - error message to return to accounts
|
||||
who already got one weapon from the rack and tries to
|
||||
grab another one.
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class CmdTutorialSetDetail(default_cmds.MuxCommand):
|
|||
multiple aliases to the detail all at once.
|
||||
"""
|
||||
key = "@detail"
|
||||
locks = "cmd:perm(Builders)"
|
||||
locks = "cmd:perm(Builder)"
|
||||
help_category = "TutorialWorld"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -126,7 +126,7 @@ class CmdTutorialLook(default_cmds.CmdLook):
|
|||
Usage:
|
||||
look <obj>
|
||||
look <room detail>
|
||||
look *<player>
|
||||
look *<account>
|
||||
|
||||
Observes your location, details at your location or objects
|
||||
in your vicinity.
|
||||
|
|
@ -182,7 +182,7 @@ class CmdTutorialLook(default_cmds.CmdLook):
|
|||
return
|
||||
|
||||
if not hasattr(looking_at_obj, 'return_appearance'):
|
||||
# this is likely due to us having a player instead
|
||||
# this is likely due to us having an account instead
|
||||
looking_at_obj = looking_at_obj.character
|
||||
if not looking_at_obj.access(caller, "view"):
|
||||
caller.msg("Could not find '%s'." % args)
|
||||
|
|
@ -232,7 +232,7 @@ class TutorialRoom(DefaultRoom):
|
|||
source_location (Object): the previous location of new_arrival.
|
||||
|
||||
"""
|
||||
if new_arrival.has_player and not new_arrival.is_superuser:
|
||||
if new_arrival.has_account and not new_arrival.is_superuser:
|
||||
# this is a character
|
||||
for obj in self.contents_get(exclude=new_arrival):
|
||||
if hasattr(obj, "at_new_arrival"):
|
||||
|
|
@ -362,7 +362,7 @@ class IntroRoom(TutorialRoom):
|
|||
super(IntroRoom, self).at_object_creation()
|
||||
self.db.tutorial_info = "The first room of the tutorial. " \
|
||||
"This assigns the health Attribute to "\
|
||||
"the player."
|
||||
"the account."
|
||||
|
||||
def at_object_receive(self, character, source_location):
|
||||
"""
|
||||
|
|
@ -372,7 +372,7 @@ class IntroRoom(TutorialRoom):
|
|||
# setup character for the tutorial
|
||||
health = self.db.char_health or 20
|
||||
|
||||
if character.has_player:
|
||||
if character.has_account:
|
||||
character.db.health = health
|
||||
character.db.health_max = health
|
||||
|
||||
|
|
@ -388,7 +388,7 @@ class IntroRoom(TutorialRoom):
|
|||
# Defines a special west-eastward "bridge"-room, a large room that takes
|
||||
# several steps to cross. It is complete with custom commands and a
|
||||
# chance of falling off the bridge. This room has no regular exits,
|
||||
# instead the exitings are handled by custom commands set on the player
|
||||
# instead the exitings are handled by custom commands set on the account
|
||||
# upon first entering the room.
|
||||
#
|
||||
# Since one can enter the bridge room from both ends, it is
|
||||
|
|
@ -537,7 +537,7 @@ class CmdLookBridge(Command):
|
|||
BRIDGE_POS_MESSAGES[bridge_position],
|
||||
random.choice(BRIDGE_MOODS))
|
||||
|
||||
chars = [obj for obj in self.obj.contents_get(exclude=caller) if obj.has_player]
|
||||
chars = [obj for obj in self.obj.contents_get(exclude=caller) if obj.has_account]
|
||||
if chars:
|
||||
# we create the You see: message manually here
|
||||
message += "\n You see: %s" % ", ".join("|c%s|n" % char.key for char in chars)
|
||||
|
|
@ -606,7 +606,7 @@ class BridgeRoom(WeatherRoom):
|
|||
The bridge room implements an unsafe bridge. It also enters the player into
|
||||
a state where they get new commands so as to try to cross the bridge.
|
||||
|
||||
We want this to result in the player getting a special set of
|
||||
We want this to result in the account getting a special set of
|
||||
commands related to crossing the bridge. The result is that it
|
||||
will take several steps to cross it, despite it being represented
|
||||
by only a single room.
|
||||
|
|
@ -659,7 +659,7 @@ class BridgeRoom(WeatherRoom):
|
|||
This hook is called by the engine whenever the player is moved
|
||||
into this room.
|
||||
"""
|
||||
if character.has_player:
|
||||
if character.has_account:
|
||||
# we only run this if the entered object is indeed a player object.
|
||||
# check so our east/west exits are correctly defined.
|
||||
wexit = search_object(self.db.west_exit)
|
||||
|
|
@ -682,7 +682,7 @@ class BridgeRoom(WeatherRoom):
|
|||
"""
|
||||
This is triggered when the player leaves the bridge room.
|
||||
"""
|
||||
if character.has_player:
|
||||
if character.has_account:
|
||||
# clean up the position attribute
|
||||
del character.db.tutorial_bridge_position
|
||||
|
||||
|
|
@ -876,7 +876,7 @@ class DarkRoom(TutorialRoom):
|
|||
self.locks.add("view:all()")
|
||||
self.cmdset.remove(DarkCmdSet)
|
||||
self.db.is_lit = True
|
||||
for char in (obj for obj in self.contents if obj.has_player):
|
||||
for char in (obj for obj in self.contents if obj.has_account):
|
||||
# this won't do anything if it is already removed
|
||||
char.msg("The room is lit up.")
|
||||
else:
|
||||
|
|
@ -884,7 +884,7 @@ class DarkRoom(TutorialRoom):
|
|||
self.db.is_lit = False
|
||||
self.locks.add("view:false()")
|
||||
self.cmdset.add(DarkCmdSet, permanent=True)
|
||||
for char in (obj for obj in self.contents if obj.has_player):
|
||||
for char in (obj for obj in self.contents if obj.has_account):
|
||||
if char.is_superuser:
|
||||
char.msg("You are Superuser, so you are not affected by the dark state.")
|
||||
else:
|
||||
|
|
@ -895,7 +895,7 @@ class DarkRoom(TutorialRoom):
|
|||
"""
|
||||
Called when an object enters the room.
|
||||
"""
|
||||
if obj.has_player:
|
||||
if obj.has_account:
|
||||
# a puppeted object, that is, a Character
|
||||
self._heal(obj)
|
||||
# in case the new guy carries light with them
|
||||
|
|
@ -960,7 +960,7 @@ class TeleportRoom(TutorialRoom):
|
|||
This hook is called by the engine whenever the player is moved into
|
||||
this room.
|
||||
"""
|
||||
if not character.has_player:
|
||||
if not character.has_account:
|
||||
# only act on player characters.
|
||||
return
|
||||
# determine if the puzzle is a success or not
|
||||
|
|
@ -1020,7 +1020,7 @@ class OutroRoom(TutorialRoom):
|
|||
"""
|
||||
Do cleanup.
|
||||
"""
|
||||
if character.has_player:
|
||||
if character.has_account:
|
||||
del character.db.health_max
|
||||
del character.db.health
|
||||
del character.db.last_climbed
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ class WildernessScript(DefaultScript):
|
|||
old_room.wilderness.at_after_object_leave(obj)
|
||||
else:
|
||||
for item in old_room.contents:
|
||||
if item.has_player:
|
||||
if item.has_account:
|
||||
# There is still a player in the old room.
|
||||
# Let's create a new room and not touch that old
|
||||
# room.
|
||||
|
|
@ -419,7 +419,7 @@ class WildernessScript(DefaultScript):
|
|||
return
|
||||
|
||||
for item in room.contents:
|
||||
if item.has_player:
|
||||
if item.has_account:
|
||||
# There is still a character in that room. We can't get rid of
|
||||
# it just yet
|
||||
break
|
||||
|
|
@ -457,7 +457,7 @@ class WildernessScript(DefaultScript):
|
|||
class WildernessRoom(DefaultRoom):
|
||||
"""
|
||||
This is a single room inside the wilderness. This room provides a "view"
|
||||
into the wilderness map. When a player moves around, instead of going to
|
||||
into the wilderness map. When an account moves around, instead of going to
|
||||
another room as with traditional rooms, they stay in the same room but the
|
||||
room itself changes to display another area of the wilderness.
|
||||
"""
|
||||
|
|
@ -588,7 +588,7 @@ class WildernessRoom(DefaultRoom):
|
|||
Displays the name of the object in a viewer-aware manner.
|
||||
|
||||
Args:
|
||||
looker (TypedObject): The object or player that is looking
|
||||
looker (TypedObject): The object or account that is looking
|
||||
at/getting inforamtion for this object.
|
||||
|
||||
Returns:
|
||||
|
|
@ -603,7 +603,7 @@ class WildernessRoom(DefaultRoom):
|
|||
searching, and is expected to produce something useful for
|
||||
builders.
|
||||
"""
|
||||
if self.locks.check_lockstring(looker, "perm(Builders)"):
|
||||
if self.locks.check_lockstring(looker, "perm(Builder)"):
|
||||
name = "{}(#{})".format(self.location_name, self.id)
|
||||
else:
|
||||
name = self.location_name
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Commands
|
||||
|
||||
Commands describe the input the player can do to the game.
|
||||
Commands describe the input the account can do to the game.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -169,17 +169,17 @@ class Command(BaseCommand):
|
|||
# self.rhs = rhs
|
||||
# self.rhslist = rhslist
|
||||
#
|
||||
# # if the class has the player_caller property set on itself, we make
|
||||
# # sure that self.caller is always the player if possible. We also create
|
||||
# # if the class has the account_caller property set on itself, we make
|
||||
# # sure that self.caller is always the account if possible. We also create
|
||||
# # a special property "character" for the puppeted object, if any. This
|
||||
# # is convenient for commands defined on the Player only.
|
||||
# if hasattr(self, "player_caller") and self.player_caller:
|
||||
# # is convenient for commands defined on the Account only.
|
||||
# if hasattr(self, "account_caller") and self.account_caller:
|
||||
# if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"):
|
||||
# # caller is an Object/Character
|
||||
# self.character = self.caller
|
||||
# self.caller = self.caller.player
|
||||
# elif utils.inherits_from(self.caller, "evennia.players.players.DefaultPlayer"):
|
||||
# # caller was already a Player
|
||||
# self.caller = self.caller.account
|
||||
# elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"):
|
||||
# # caller was already an Account
|
||||
# self.character = self.caller.get_puppet(self.session)
|
||||
# else:
|
||||
# self.character = None
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
|||
"""
|
||||
The `CharacterCmdSet` contains general in-game commands like `look`,
|
||||
`get`, etc available on in-game Character objects. It is merged with
|
||||
the `PlayerCmdSet` when a Player puppets a Character.
|
||||
the `AccountCmdSet` when an Account puppets a Character.
|
||||
"""
|
||||
key = "DefaultCharacter"
|
||||
|
||||
|
|
@ -34,20 +34,20 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
|||
#
|
||||
|
||||
|
||||
class PlayerCmdSet(default_cmds.PlayerCmdSet):
|
||||
class AccountCmdSet(default_cmds.AccountCmdSet):
|
||||
"""
|
||||
This is the cmdset available to the Player at all times. It is
|
||||
combined with the `CharacterCmdSet` when the Player puppets a
|
||||
This is the cmdset available to the Account at all times. It is
|
||||
combined with the `CharacterCmdSet` when the Account puppets a
|
||||
Character. It holds game-account-specific commands, channel
|
||||
commands, etc.
|
||||
"""
|
||||
key = "DefaultPlayer"
|
||||
key = "DefaultAccount"
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
"""
|
||||
Populates the cmdset
|
||||
"""
|
||||
super(PlayerCmdSet, self).at_cmdset_creation()
|
||||
super(AccountCmdSet, self).at_cmdset_creation()
|
||||
#
|
||||
# any commands you add below will overload the default ones.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ The serversession is the Server-side in-memory representation of a
|
|||
user connecting to the game. Evennia manages one Session per
|
||||
connection to the game. So a user logged into the game with multiple
|
||||
clients (if Evennia is configured to allow that) will have multiple
|
||||
sessions tied to one Player object. All communication between Evennia
|
||||
sessions tied to one Account object. All communication between Evennia
|
||||
and the real-world user goes through the Session(s) associated with that user.
|
||||
|
||||
It should be noted that modifying the Session object is not usually
|
||||
|
|
@ -28,8 +28,8 @@ class ServerSession(BaseServerSession):
|
|||
This class represents a player's session and is a template for
|
||||
individual protocols to communicate with Evennia.
|
||||
|
||||
Each player gets one or more sessions assigned to them whenever they connect
|
||||
to the game server. All communication between game and player goes
|
||||
Each account gets one or more sessions assigned to them whenever they connect
|
||||
to the game server. All communication between game and account goes
|
||||
through their session(s).
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
"""
|
||||
Player
|
||||
Account
|
||||
|
||||
The Player represents the game "account" and each login has only one
|
||||
Player object. A Player is what chats on default channels but has no
|
||||
other in-game-world existence. Rather the Player puppets Objects (such
|
||||
The Account represents the game "account" and each login has only one
|
||||
Account object. An Account is what chats on default channels but has no
|
||||
other in-game-world existence. Rather the Account puppets Objects (such
|
||||
as Characters) in order to actually participate in the game world.
|
||||
|
||||
|
||||
Guest
|
||||
|
||||
Guest players are simple low-level accounts that are created/deleted
|
||||
Guest accounts are simple low-level accounts that are created/deleted
|
||||
on the fly and allows users to test the game without the commitment
|
||||
of a full registration. Guest accounts are deactivated by default; to
|
||||
activate them, add the following line to your settings file:
|
||||
|
|
@ -22,11 +22,11 @@ several more options for customizing the Guest account system.
|
|||
|
||||
"""
|
||||
|
||||
from evennia import DefaultPlayer, DefaultGuest
|
||||
from evennia import DefaultAccount, DefaultGuest
|
||||
|
||||
class Player(DefaultPlayer):
|
||||
class Account(DefaultAccount):
|
||||
"""
|
||||
This class describes the actual OOC player (i.e. the user connecting
|
||||
This class describes the actual OOC account (i.e. the user connecting
|
||||
to the MUD). It does NOT have visual appearance in the game world (that
|
||||
is handled by the character which is connected to this). Comm channels
|
||||
are attended/joined using this object.
|
||||
|
|
@ -35,12 +35,12 @@ class Player(DefaultPlayer):
|
|||
should generally not hold any character-related info (that's best handled
|
||||
on the character level).
|
||||
|
||||
Can be set using BASE_PLAYER_TYPECLASS.
|
||||
Can be set using BASE_ACCOUNT_TYPECLASS.
|
||||
|
||||
|
||||
* available properties
|
||||
|
||||
key (string) - name of player
|
||||
key (string) - name of account
|
||||
name (string)- wrapper for user.username
|
||||
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
||||
dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
||||
|
|
@ -48,8 +48,8 @@ class Player(DefaultPlayer):
|
|||
permissions (list of strings) - list of permission strings
|
||||
|
||||
user (User, read-only) - django User authorization object
|
||||
obj (Object) - game object controlled by player. 'character' can also be used.
|
||||
sessions (list of Sessions) - sessions connected to this player
|
||||
obj (Object) - game object controlled by account. 'character' can also be used.
|
||||
sessions (list of Sessions) - sessions connected to this account
|
||||
is_superuser (bool, read-only) - if the connected user is a superuser
|
||||
|
||||
* Handlers
|
||||
|
|
@ -66,7 +66,7 @@ class Player(DefaultPlayer):
|
|||
msg(text=None, **kwargs)
|
||||
swap_character(new_character, delete_old_character=False)
|
||||
execute_cmd(raw_string, session=None)
|
||||
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False)
|
||||
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, account=False)
|
||||
is_typeclass(typeclass, exact=False)
|
||||
swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
|
||||
access(accessing_obj, access_type='read', default=False)
|
||||
|
|
@ -75,7 +75,7 @@ class Player(DefaultPlayer):
|
|||
* Hook methods (when re-implementation, remember methods need to have self as first arg)
|
||||
|
||||
basetype_setup()
|
||||
at_player_creation()
|
||||
at_account_creation()
|
||||
|
||||
- note that the following hooks are also found on Objects and are
|
||||
usually handled on the character level:
|
||||
|
|
@ -96,7 +96,7 @@ class Player(DefaultPlayer):
|
|||
|
||||
class Guest(DefaultGuest):
|
||||
"""
|
||||
This class is used for guest logins. Unlike Players, Guests and their
|
||||
This class is used for guest logins. Unlike Accounts, Guests and their
|
||||
characters are deleted after disconnection.
|
||||
"""
|
||||
pass
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
Channel
|
||||
|
||||
The channel class represents the out-of-character chat-room usable by
|
||||
Players in-game. It is mostly overloaded to change its appearance, but
|
||||
Accounts in-game. It is mostly overloaded to change its appearance, but
|
||||
channels can be used to implement many different forms of message
|
||||
distribution systems.
|
||||
|
||||
|
|
@ -18,9 +18,9 @@ class Channel(DefaultChannel):
|
|||
"""
|
||||
Working methods:
|
||||
at_channel_creation() - called once, when the channel is created
|
||||
has_connection(player) - check if the given player listens to this channel
|
||||
connect(player) - connect player to this channel
|
||||
disconnect(player) - disconnect player from channel
|
||||
has_connection(account) - check if the given account listens to this channel
|
||||
connect(account) - connect account to this channel
|
||||
disconnect(account) - disconnect account from channel
|
||||
access(access_obj, access_type='listen', default=False) - check the
|
||||
access on this channel (default access_type is listen)
|
||||
delete() - delete this channel
|
||||
|
|
@ -33,8 +33,8 @@ class Channel(DefaultChannel):
|
|||
tempmsg(msg, header=None, senders=None) - wrapper for sending non-persistent
|
||||
messages.
|
||||
distribute_message(msg, online=False) - send a message to all
|
||||
connected players on channel, optionally sending only
|
||||
to players that are currently online (optimized for very large sends)
|
||||
connected accounts on channel, optionally sending only
|
||||
to accounts that are currently online (optimized for very large sends)
|
||||
|
||||
Useful hooks:
|
||||
channel_prefix(msg, emit=False) - how the channel should be
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Characters
|
||||
|
||||
Characters are (by default) Objects setup to be puppeted by Players.
|
||||
Characters are (by default) Objects setup to be puppeted by Accounts.
|
||||
They are what you "see" in game. The Character class in this module
|
||||
is setup to be the "default" character type created by the default
|
||||
creation commands.
|
||||
|
|
@ -19,14 +19,14 @@ class Character(DefaultCharacter):
|
|||
and its commands only be called by itself, not anyone else.
|
||||
(to change things, use at_object_creation() instead).
|
||||
at_after_move(source_location) - Launches the "look" command after every move.
|
||||
at_post_unpuppet(player) - when Player disconnects from the Character, we
|
||||
at_post_unpuppet(account) - when Account disconnects from the Character, we
|
||||
store the current location in the pre_logout_location Attribute and
|
||||
move it to a None-location so the "unpuppeted" character
|
||||
object does not need to stay on grid. Echoes "Player has disconnected"
|
||||
object does not need to stay on grid. Echoes "Account has disconnected"
|
||||
to the room.
|
||||
at_pre_puppet - Just before Player re-connects, retrieves the character's
|
||||
at_pre_puppet - Just before Account re-connects, retrieves the character's
|
||||
pre_logout_location Attribute and move it back on the grid.
|
||||
at_post_puppet - Echoes "PlayerName has entered the game" to the room.
|
||||
at_post_puppet - Echoes "AccountName has entered the game" to the room.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -40,16 +40,16 @@ class Object(DefaultObject):
|
|||
date_created (string) - time stamp of object creation
|
||||
permissions (list of strings) - list of permission strings
|
||||
|
||||
player (Player) - controlling player (if any, only set together with
|
||||
account (Account) - controlling account (if any, only set together with
|
||||
sessid below)
|
||||
sessid (int, read-only) - session id (if any, only set together with
|
||||
player above). Use `sessions` handler to get the
|
||||
account above). Use `sessions` handler to get the
|
||||
Sessions directly.
|
||||
location (Object) - current location. Is None if this is a room
|
||||
home (Object) - safety start-location
|
||||
sessions (list of Sessions, read-only) - returns all sessions connected
|
||||
to this object
|
||||
has_player (bool, read-only)- will only return *connected* players
|
||||
has_account (bool, read-only)- will only return *connected* accounts
|
||||
contents (list of Objects, read-only) - returns all objects inside this
|
||||
object (including exits)
|
||||
exits (list of Objects, read-only) - returns all exits from this
|
||||
|
|
@ -73,7 +73,7 @@ class Object(DefaultObject):
|
|||
* Helper methods (see src.objects.objects.py for full headers)
|
||||
|
||||
search(ostring, global_search=False, attribute_name=None,
|
||||
use_nicks=False, location=None, ignore_errors=False, player=False)
|
||||
use_nicks=False, location=None, ignore_errors=False, account=False)
|
||||
execute_cmd(raw_string)
|
||||
msg(text=None, **kwargs)
|
||||
msg_contents(message, exclude=None, from_obj=None, **kwargs)
|
||||
|
|
@ -105,14 +105,14 @@ class Object(DefaultObject):
|
|||
requests a cmdset from this object. The kwargs are
|
||||
not normally used unless the cmdset is created
|
||||
dynamically (see e.g. Exits).
|
||||
at_pre_puppet(player)- (player-controlled objects only) called just
|
||||
at_pre_puppet(account)- (account-controlled objects only) called just
|
||||
before puppeting
|
||||
at_post_puppet() - (player-controlled objects only) called just
|
||||
after completing connection player<->object
|
||||
at_pre_unpuppet() - (player-controlled objects only) called just
|
||||
at_post_puppet() - (account-controlled objects only) called just
|
||||
after completing connection account<->object
|
||||
at_pre_unpuppet() - (account-controlled objects only) called just
|
||||
before un-puppeting
|
||||
at_post_unpuppet(player) - (player-controlled objects only) called just
|
||||
after disconnecting player<->object link
|
||||
at_post_unpuppet(account) - (account-controlled objects only) called just
|
||||
after disconnecting account<->object link
|
||||
at_server_reload() - called before server is reloaded
|
||||
at_server_shutdown() - called just before server is fully shut down
|
||||
|
||||
|
|
|
|||
20
evennia/help/migrations/0002_auto_20170606_1731.py
Normal file
20
evennia/help/migrations/0002_auto_20170606_1731.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-06 17:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('help', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='helpentry',
|
||||
name='db_tags',
|
||||
field=models.ManyToManyField(blank=True, help_text=b'tags on this object. Tags are simple string markers to identify, group and alias objects.', to='typeclasses.Tag'),
|
||||
),
|
||||
]
|
||||
|
|
@ -58,7 +58,7 @@ class HelpEntry(SharedMemoryModel):
|
|||
# lock string storage
|
||||
db_lock_storage = models.TextField('locks', blank=True, help_text='normally view:all().')
|
||||
# tags are primarily used for permissions
|
||||
db_tags = models.ManyToManyField(Tag, null=True,
|
||||
db_tags = models.ManyToManyField(Tag, blank=True,
|
||||
help_text='tags on this object. Tags are simple string markers to identify, group and alias objects.')
|
||||
# (deprecated, only here to allow MUX helpfile load (don't use otherwise)).
|
||||
# TODO: remove this when not needed anymore.
|
||||
|
|
|
|||
|
|
@ -28,38 +28,38 @@ MUX Name: Affects: Effect:
|
|||
DefaultLock: Exits: controls who may traverse the exit to
|
||||
its destination.
|
||||
Evennia: "traverse:<lockfunc()>"
|
||||
Rooms: controls whether the player sees the
|
||||
Rooms: controls whether the account sees the
|
||||
SUCC or FAIL message for the room
|
||||
following the room description when
|
||||
looking at the room.
|
||||
Evennia: Custom typeclass
|
||||
Players/Things: controls who may GET the object.
|
||||
Accounts/Things: controls who may GET the object.
|
||||
Evennia: "get:<lockfunc()"
|
||||
EnterLock: Players/Things: controls who may ENTER the object
|
||||
EnterLock: Accounts/Things: controls who may ENTER the object
|
||||
Evennia:
|
||||
GetFromLock: All but Exits: controls who may gets things from a
|
||||
given location.
|
||||
Evennia:
|
||||
GiveLock: Players/Things: controls who may give the object.
|
||||
GiveLock: Accounts/Things: controls who may give the object.
|
||||
Evennia:
|
||||
LeaveLock: Players/Things: controls who may LEAVE the object.
|
||||
LeaveLock: Accounts/Things: controls who may LEAVE the object.
|
||||
Evennia:
|
||||
LinkLock: All but Exits: controls who may link to the location
|
||||
if the location is LINK_OK (for linking
|
||||
exits or setting drop-tos) or ABODE (for
|
||||
setting homes)
|
||||
Evennia:
|
||||
MailLock: Players: controls who may @mail the player.
|
||||
MailLock: Accounts: controls who may @mail the account.
|
||||
Evennia:
|
||||
OpenLock: All but Exits: controls who may open an exit.
|
||||
Evennia:
|
||||
PageLock: Players: controls who may page the player.
|
||||
PageLock: Accounts: controls who may page the account.
|
||||
Evennia: "send:<lockfunc()>"
|
||||
ParentLock: All: controls who may make @parent links to
|
||||
the object.
|
||||
Evennia: Typeclasses and
|
||||
"puppet:<lockstring()>"
|
||||
ReceiveLock: Players/Things: controls who may give things to the
|
||||
ReceiveLock: Accounts/Things: controls who may give things to the
|
||||
object.
|
||||
Evennia:
|
||||
SpeechLock: All but Exits: controls who may speak in that location
|
||||
|
|
@ -95,11 +95,11 @@ from evennia.utils import utils
|
|||
_PERMISSION_HIERARCHY = [pe.lower() for pe in settings.PERMISSION_HIERARCHY]
|
||||
|
||||
|
||||
def _to_player(accessing_obj):
|
||||
"Helper function. Makes sure an accessing object is a player object"
|
||||
def _to_account(accessing_obj):
|
||||
"Helper function. Makes sure an accessing object is an account object"
|
||||
if utils.inherits_from(accessing_obj, "evennia.objects.objects.DefaultObject"):
|
||||
# an object. Convert to player.
|
||||
accessing_obj = accessing_obj.player
|
||||
# an object. Convert to account.
|
||||
accessing_obj = accessing_obj.account
|
||||
return accessing_obj
|
||||
|
||||
|
||||
|
|
@ -149,11 +149,11 @@ def perm(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
If the given permission is part of settings.PERMISSION_HIERARCHY,
|
||||
permission is also granted to all ranks higher up in the hierarchy.
|
||||
|
||||
If accessing_object is an Object controlled by a Player, the
|
||||
permissions of the Player is used unless the Attribute _quell
|
||||
If accessing_object is an Object controlled by an Account, the
|
||||
permissions of the Account is used unless the Attribute _quell
|
||||
is set to True on the Object. In this case however, the
|
||||
LOWEST hieararcy-permission of the Player/Object-pair will be used
|
||||
(this is order to avoid Players potentially escalating their own permissions
|
||||
LOWEST hieararcy-permission of the Account/Object-pair will be used
|
||||
(this is order to avoid Accounts potentially escalating their own permissions
|
||||
by use of a higher-level Object)
|
||||
|
||||
"""
|
||||
|
|
@ -166,29 +166,30 @@ def perm(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
except (AttributeError, IndexError):
|
||||
return False
|
||||
|
||||
if utils.inherits_from(accessing_obj, "evennia.objects.objects.DefaultObject") and accessing_obj.player:
|
||||
player = accessing_obj.player
|
||||
perms_player = [p.lower() for p in player.permissions.all()]
|
||||
is_quell = player.attributes.get("_quell")
|
||||
if utils.inherits_from(accessing_obj, "evennia.objects.objects.DefaultObject") and accessing_obj.account:
|
||||
account = accessing_obj.account
|
||||
# we strip eventual plural forms, so Builders == Builder
|
||||
perms_account = [p.lower().rstrip("s") for p in account.permissions.all()]
|
||||
is_quell = account.attributes.get("_quell")
|
||||
|
||||
if permission in _PERMISSION_HIERARCHY:
|
||||
# check hierarchy without allowing escalation obj->player
|
||||
# check hierarchy without allowing escalation obj->account
|
||||
hpos_target = _PERMISSION_HIERARCHY.index(permission)
|
||||
hpos_player = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_player]
|
||||
hpos_player = hpos_player and hpos_player[-1] or -1
|
||||
hpos_account = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_account]
|
||||
hpos_account = hpos_account and hpos_account[-1] or -1
|
||||
if is_quell:
|
||||
hpos_object = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_object]
|
||||
hpos_object = hpos_object and hpos_object[-1] or -1
|
||||
if gtmode:
|
||||
return hpos_target < min(hpos_player, hpos_object)
|
||||
return hpos_target < min(hpos_account, hpos_object)
|
||||
else:
|
||||
return hpos_target <= min(hpos_player, hpos_object)
|
||||
return hpos_target <= min(hpos_account, hpos_object)
|
||||
elif gtmode:
|
||||
return hpos_target < hpos_player
|
||||
return hpos_target < hpos_account
|
||||
else:
|
||||
return hpos_target <= hpos_player
|
||||
elif not is_quell and permission in perms_player:
|
||||
# if we get here, check player perms first, otherwise
|
||||
return hpos_target <= hpos_account
|
||||
elif not is_quell and permission in perms_account:
|
||||
# if we get here, check account perms first, otherwise
|
||||
# continue as normal
|
||||
return True
|
||||
|
||||
|
|
@ -216,7 +217,7 @@ def perm_above(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
|
||||
def pperm(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"""
|
||||
The basic permission-checker only for Player objects. Ignores case.
|
||||
The basic permission-checker only for Account objects. Ignores case.
|
||||
|
||||
Usage:
|
||||
pperm(<permission>)
|
||||
|
|
@ -226,17 +227,17 @@ def pperm(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
is part of _PERMISSION_HIERARCHY, permission is also granted
|
||||
to all ranks higher up in the hierarchy.
|
||||
"""
|
||||
return perm(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
return perm(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
|
||||
|
||||
def pperm_above(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"""
|
||||
Only allow Player objects with a permission *higher* in the permission
|
||||
Only allow Account objects with a permission *higher* in the permission
|
||||
hierarchy than the one given. If there is no such higher rank,
|
||||
it's assumed we refer to superuser. If no hierarchy is defined,
|
||||
this function has no meaning and returns False.
|
||||
"""
|
||||
return perm_above(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
return perm_above(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
|
||||
|
||||
def dbref(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
|
|
@ -262,9 +263,9 @@ def dbref(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
|
||||
def pdbref(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"""
|
||||
Same as dbref, but making sure accessing_obj is a player.
|
||||
Same as dbref, but making sure accessing_obj is an account.
|
||||
"""
|
||||
return dbref(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
return dbref(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
|
||||
|
||||
def id(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
|
|
@ -273,8 +274,8 @@ def id(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
|
||||
|
||||
def pid(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"Alias to dbref, for Players"
|
||||
return dbref(_to_player(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
"Alias to dbref, for Accounts"
|
||||
return dbref(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
|
||||
|
||||
|
||||
# this is more efficient than multiple if ... elif statments
|
||||
|
|
@ -565,15 +566,15 @@ def superuser(*args, **kwargs):
|
|||
"""
|
||||
return False
|
||||
|
||||
def has_player(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
def has_account(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"""
|
||||
Only returns true if accessing_obj has_player is true, that is,
|
||||
this is a player-controlled object. It fails on actual players!
|
||||
Only returns true if accessing_obj has_account is true, that is,
|
||||
this is an account-controlled object. It fails on actual accounts!
|
||||
|
||||
This is a useful lock for traverse-locking Exits to restrain NPC
|
||||
mobiles from moving outside their areas.
|
||||
"""
|
||||
return hasattr(accessing_obj, "has_player") and accessing_obj.has_player
|
||||
return hasattr(accessing_obj, "has_account") and accessing_obj.has_account
|
||||
|
||||
def serversetting(accessing_obj, accessed_obj, *args, **kwargs):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -56,21 +56,21 @@ Example:
|
|||
|
||||
We want to limit who may edit a particular object (let's call this access_type
|
||||
for 'edit', it depends on what the command is looking for). We want this to
|
||||
only work for those with the Permission 'Builders'. So we use our lock
|
||||
only work for those with the Permission 'Builder'. So we use our lock
|
||||
function above and define it like this:
|
||||
|
||||
'edit:perm(Builders)'
|
||||
'edit:perm(Builder)'
|
||||
|
||||
Here, the lock-function perm() will be called with the string
|
||||
'Builders' (accessing_obj and accessed_obj are added automatically,
|
||||
'Builder' (accessing_obj and accessed_obj are added automatically,
|
||||
you only need to add the args/kwargs, if any).
|
||||
|
||||
If we wanted to make sure the accessing object was BOTH a Builders and a
|
||||
If we wanted to make sure the accessing object was BOTH a Builder and a
|
||||
GoodGuy, we could use AND:
|
||||
|
||||
'edit:perm(Builders) AND perm(GoodGuy)'
|
||||
'edit:perm(Builder) AND perm(GoodGuy)'
|
||||
|
||||
To allow EITHER Builders and GoodGuys, we replace AND with OR. perm() is just
|
||||
To allow EITHER Builder and GoodGuys, we replace AND with OR. perm() is just
|
||||
one example, the lock function can do anything and compare any properties of
|
||||
the calling object to decide if the lock is passed or not.
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ the calling object to decide if the lock is passed or not.
|
|||
To make these work, add the string to the lockhandler of the object you want
|
||||
to apply the lock to:
|
||||
|
||||
obj.lockhandler.add('edit:perm(Builders)')
|
||||
obj.lockhandler.add('edit:perm(Builder)')
|
||||
|
||||
From then on, a command that wants to check for 'edit' access on this
|
||||
object would do something like this:
|
||||
|
|
@ -271,10 +271,10 @@ class LockHandler(object):
|
|||
def cache_lock_bypass(self, obj):
|
||||
"""
|
||||
We cache superuser bypass checks here for efficiency. This
|
||||
needs to be re-run when a player is assigned to a character.
|
||||
needs to be re-run when an account is assigned to a character.
|
||||
We need to grant access to superusers. We need to check both
|
||||
directly on the object (players), through obj.player and using
|
||||
the get_player() method (this sits on serversessions, in some
|
||||
directly on the object (accounts), through obj.account and using
|
||||
the get_account() method (this sits on serversessions, in some
|
||||
rare cases where a check is done before the login process has
|
||||
yet been fully finalized)
|
||||
|
||||
|
|
@ -450,8 +450,8 @@ class LockHandler(object):
|
|||
except AttributeError:
|
||||
# happens before session is initiated.
|
||||
if not no_superuser_bypass and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser)
|
||||
or (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser)
|
||||
or (hasattr(accessing_obj, 'get_player') and (not accessing_obj.get_player() or accessing_obj.get_player().is_superuser))):
|
||||
or (hasattr(accessing_obj, 'account') and hasattr(accessing_obj.account, 'is_superuser') and accessing_obj.account.is_superuser)
|
||||
or (hasattr(accessing_obj, 'get_account') and (not accessing_obj.get_account() or accessing_obj.get_account().is_superuser))):
|
||||
return True
|
||||
|
||||
# no superuser or bypass -> normal lock operation
|
||||
|
|
@ -511,8 +511,8 @@ class LockHandler(object):
|
|||
return True
|
||||
except AttributeError:
|
||||
if no_superuser_bypass and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser)
|
||||
or (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser)
|
||||
or (hasattr(accessing_obj, 'get_player') and (not accessing_obj.get_player() or accessing_obj.get_player().is_superuser))):
|
||||
or (hasattr(accessing_obj, 'account') and hasattr(accessing_obj.account, 'is_superuser') and accessing_obj.account.is_superuser)
|
||||
or (hasattr(accessing_obj, 'get_account') and (not accessing_obj.get_account() or accessing_obj.get_account().is_superuser))):
|
||||
return True
|
||||
if not ":" in lockstring:
|
||||
lockstring = "%s:%s" % ("_dummy", lockstring)
|
||||
|
|
@ -541,13 +541,13 @@ def _test():
|
|||
obj1 = TestObj()
|
||||
obj2 = TestObj()
|
||||
|
||||
#obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Wizards);examine:perm(Builders);delete:perm(Wizards);get:all()"
|
||||
#obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Admin);examine:perm(Builder);delete:perm(Admin);get:all()"
|
||||
#obj1.lock_storage = "cmd:all();admin:id(1);listen:all();send:all()"
|
||||
obj1.lock_storage = "listen:perm(Immortals)"
|
||||
obj1.lock_storage = "listen:perm(Developer)"
|
||||
|
||||
pdb.set_trace()
|
||||
obj1.locks = LockHandler(obj1)
|
||||
obj2.permissions.add("Immortals")
|
||||
obj2.permissions.add("Developer")
|
||||
obj2.id = 4
|
||||
|
||||
#obj1.locks.add("edit:attr(test)")
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ from evennia.locks import lockfuncs
|
|||
class TestLockCheck(EvenniaTest):
|
||||
def testrun(self):
|
||||
dbref = self.obj2.dbref
|
||||
self.obj1.locks.add("owner:dbref(%s);edit:dbref(%s) or perm(Wizards);examine:perm(Builders) and id(%s);delete:perm(Wizards);get:all()" % (dbref, dbref, dbref))
|
||||
self.obj2.permissions.add('Wizards')
|
||||
self.obj1.locks.add("owner:dbref(%s);edit:dbref(%s) or perm(Admin);examine:perm(Builder) and id(%s);delete:perm(Admin);get:all()" % (dbref, dbref, dbref))
|
||||
self.obj2.permissions.add('Admin')
|
||||
self.assertEquals(True, self.obj1.locks.check(self.obj2, 'owner'))
|
||||
self.assertEquals(True, self.obj1.locks.check(self.obj2, 'edit'))
|
||||
self.assertEquals(True, self.obj1.locks.check(self.obj2, 'examine'))
|
||||
|
|
@ -39,11 +39,11 @@ class TestLockCheck(EvenniaTest):
|
|||
|
||||
class TestLockfuncs(EvenniaTest):
|
||||
def testrun(self):
|
||||
self.obj2.permissions.add('Wizards')
|
||||
self.obj2.permissions.add('Admin')
|
||||
self.assertEquals(True, lockfuncs.true(self.obj2, self.obj1))
|
||||
self.assertEquals(False, lockfuncs.false(self.obj2, self.obj1))
|
||||
self.assertEquals(True, lockfuncs.perm(self.obj2, self.obj1, 'Wizards'))
|
||||
self.assertEquals(True, lockfuncs.perm_above(self.obj2, self.obj1, 'Builders'))
|
||||
self.assertEquals(True, lockfuncs.perm(self.obj2, self.obj1, 'Admin'))
|
||||
self.assertEquals(True, lockfuncs.perm_above(self.obj2, self.obj1, 'Builder'))
|
||||
dbref = self.obj2.dbref
|
||||
self.assertEquals(True, lockfuncs.dbref(self.obj2, self.obj1, '%s' % dbref))
|
||||
self.obj2.db.testattr = 45
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ class ObjectDBAdmin(admin.ModelAdmin):
|
|||
"""
|
||||
|
||||
inlines = [ObjectTagInline, ObjectAttributeInline]
|
||||
list_display = ('id', 'db_key', 'db_player', 'db_typeclass_path')
|
||||
list_display = ('id', 'db_key', 'db_account', 'db_typeclass_path')
|
||||
list_display_links = ('id', 'db_key')
|
||||
ordering = ['db_player', 'db_typeclass_path', 'id']
|
||||
ordering = ['db_account', 'db_typeclass_path', 'id']
|
||||
search_fields = ['^db_key', 'db_typeclass_path']
|
||||
raw_id_fields = ('db_destination', 'db_location', 'db_home')
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ from django.db.models import Q
|
|||
from django.conf import settings
|
||||
from django.db.models.fields import exceptions
|
||||
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
||||
from evennia.typeclasses.managers import returns_typeclass, returns_typeclass_list
|
||||
from evennia.utils.utils import to_unicode, is_iter, make_iter, string_partial_matching
|
||||
from builtins import int
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ class ObjectDBManager(TypedObjectManager):
|
|||
get_dbref_range
|
||||
object_totals
|
||||
typeclass_search
|
||||
get_object_with_player
|
||||
get_object_with_account
|
||||
get_objs_with_key_and_typeclass
|
||||
get_objs_with_attr
|
||||
get_objs_with_attr_match
|
||||
|
|
@ -54,19 +53,18 @@ class ObjectDBManager(TypedObjectManager):
|
|||
# ObjectManager Get methods
|
||||
#
|
||||
|
||||
# player related
|
||||
# account related
|
||||
|
||||
@returns_typeclass
|
||||
def get_object_with_player(self, ostring, exact=True, candidates=None):
|
||||
def get_object_with_account(self, ostring, exact=True, candidates=None):
|
||||
"""
|
||||
Search for an object based on its player's name or dbref.
|
||||
Search for an object based on its account's name or dbref.
|
||||
|
||||
Args:
|
||||
ostring (str or int): Search criterion or dbref. Searching
|
||||
for a player is sometimes initiated by appending an `*` to
|
||||
for an account is sometimes initiated by appending an `*` to
|
||||
the beginning of the search criterion (e.g. in
|
||||
local_and_global_search). This is stripped here.
|
||||
exact (bool, optional): Require an exact player match.
|
||||
exact (bool, optional): Require an exact account match.
|
||||
candidates (list, optional): Only search among this list of possible
|
||||
object candidates.
|
||||
|
||||
|
|
@ -83,9 +81,9 @@ class ObjectDBManager(TypedObjectManager):
|
|||
cand_restriction = candidates is not None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates)
|
||||
if obj]) or Q()
|
||||
if exact:
|
||||
return self.filter(cand_restriction & Q(db_player__username__iexact=ostring))
|
||||
return self.filter(cand_restriction & Q(db_account__username__iexact=ostring))
|
||||
else: # fuzzy matching
|
||||
ply_cands = self.filter(cand_restriction & Q(playerdb__username__istartswith=ostring)
|
||||
ply_cands = self.filter(cand_restriction & Q(accountdb__username__istartswith=ostring)
|
||||
).values_list("db_key", flat=True)
|
||||
if candidates:
|
||||
index_matches = string_partial_matching(ply_cands, ostring, ret_index=True)
|
||||
|
|
@ -93,7 +91,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
else:
|
||||
return string_partial_matching(ply_cands, ostring, ret_index=False)
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_key_and_typeclass(self, oname, otypeclass_path, candidates=None):
|
||||
"""
|
||||
Returns objects based on simultaneous key and typeclass match.
|
||||
|
|
@ -112,7 +109,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
|
||||
# attr/property related
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_attr(self, attribute_name, candidates=None):
|
||||
"""
|
||||
Get objects based on having a certain Attribute defined.
|
||||
|
|
@ -130,7 +126,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
if obj]) or Q()
|
||||
return list(self.filter(cand_restriction & Q(db_attributes__db_key=attribute_name)))
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_attr_value(self, attribute_name, attribute_value, candidates=None, typeclasses=None):
|
||||
"""
|
||||
Get all objects having the given attrname set to the given value.
|
||||
|
|
@ -169,7 +164,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
db_value=attribute_value)]
|
||||
return chain(*results)
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_db_property(self, property_name, candidates=None):
|
||||
"""
|
||||
Get all objects having a given db field property.
|
||||
|
|
@ -191,7 +185,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
except exceptions.FieldError:
|
||||
return []
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_db_property_value(self, property_name, property_value, candidates=None, typeclasses=None):
|
||||
"""
|
||||
Get objects with a specific field name and value.
|
||||
|
|
@ -222,7 +215,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
(property_name, type(property_value)))
|
||||
return []
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_contents(self, location, excludeobj=None):
|
||||
"""
|
||||
Get all objects that has a location set to this one.
|
||||
|
|
@ -238,7 +230,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
exclude_restriction = Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q()
|
||||
return self.filter(db_location=location).exclude(exclude_restriction)
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_key_or_alias(self, ostring, exact=True,
|
||||
candidates=None, typeclasses=None):
|
||||
"""
|
||||
|
|
@ -303,7 +294,6 @@ class ObjectDBManager(TypedObjectManager):
|
|||
|
||||
# main search methods and helper functions
|
||||
|
||||
@returns_typeclass_list
|
||||
def search_object(self, searchdata,
|
||||
attribute_name=None,
|
||||
typeclass=None,
|
||||
|
|
@ -431,6 +421,7 @@ class ObjectDBManager(TypedObjectManager):
|
|||
return matches
|
||||
# alias for backwards compatibility
|
||||
object_search = search_object
|
||||
search = search_object
|
||||
|
||||
#
|
||||
# ObjectManager Copy method
|
||||
|
|
@ -512,7 +503,7 @@ class ObjectDBManager(TypedObjectManager):
|
|||
def clear_all_sessids(self):
|
||||
"""
|
||||
Clear the db_sessid field of all objects having also the
|
||||
db_player field set.
|
||||
db_account field set.
|
||||
"""
|
||||
self.filter(db_sessid__isnull=False).update(db_sessid=None)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import django.db.models.deletion
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('typeclasses', '0001_initial'),
|
||||
('typeclasses', '0002_auto_20150109_0913'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
|
@ -20,7 +20,7 @@ class Migration(migrations.Migration):
|
|||
('db_typeclass_path', models.CharField(help_text=b"this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.", max_length=255, null=True, verbose_name=b'typeclass')),
|
||||
('db_date_created', models.DateTimeField(auto_now_add=True, verbose_name=b'creation date')),
|
||||
('db_lock_storage', models.TextField(help_text=b"locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.", verbose_name=b'locks', blank=True)),
|
||||
('db_sessid', models.CommaSeparatedIntegerField(help_text=b'csv list of session ids of connected Player, if any.', max_length=32, null=True, verbose_name=b'session id')),
|
||||
('db_sessid', models.CommaSeparatedIntegerField(help_text=b'csv list of session ids of connected Account, if any.', max_length=32, null=True, verbose_name=b'session id')),
|
||||
('db_cmdset_storage', models.CharField(help_text=b'optional python path to a cmdset class.', max_length=255, null=True, verbose_name=b'cmdset', blank=True)),
|
||||
('db_attributes', models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute', null=True)),
|
||||
('db_destination', models.ForeignKey(related_name=b'destinations_set', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='objects.ObjectDB', help_text=b'a destination, used only by exit objects.', null=True, verbose_name=b'destination')),
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ class Migration(migrations.Migration):
|
|||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='objectdb',
|
||||
name='db_player',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name=b'player', to=settings.AUTH_USER_MODEL, help_text=b'a Player connected to this object, if any.', null=True),
|
||||
name='db_account',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name=b'account', to=settings.AUTH_USER_MODEL, help_text=b'an Account connected to this object, if any.', null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
|
|
|
|||
32
evennia/objects/migrations/0006_auto_20170606_1731.py
Normal file
32
evennia/objects/migrations/0006_auto_20170606_1731.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-06 17:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import re
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('objects', '0005_auto_20150403_2339'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='objectdb',
|
||||
name='db_attributes',
|
||||
field=models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='objectdb',
|
||||
name='db_sessid',
|
||||
field=models.CharField(help_text=b'csv list of session ids of connected Account, if any.', max_length=32, null=True, validators=[django.core.validators.RegexValidator(re.compile('^\\d+(?:\\,\\d+)*\\Z'), code='invalid', message='Enter only digits separated by commas.')], verbose_name=b'session id'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='objectdb',
|
||||
name='db_tags',
|
||||
field=models.ManyToManyField(help_text=b'tags on this object. Tags are simple string markers to identify, group and alias objects.', to='typeclasses.Tag'),
|
||||
),
|
||||
]
|
||||
22
evennia/objects/migrations/0007_objectdb_db_account.py
Normal file
22
evennia/objects/migrations/0007_objectdb_db_account.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-05 17:27
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0007_copy_player_to_account'),
|
||||
('objects', '0006_auto_20170606_1731'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='objectdb',
|
||||
name='db_account',
|
||||
field=models.ForeignKey(help_text=b'an Account connected to this object, if any.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.AccountDB', verbose_name=b'account'),
|
||||
),
|
||||
]
|
||||
32
evennia/objects/migrations/0008_auto_20170705_1736.py
Normal file
32
evennia/objects/migrations/0008_auto_20170705_1736.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-05 17:36
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
|
||||
try:
|
||||
apps.get_model('accounts', 'AccountDB')
|
||||
except LookupError:
|
||||
return
|
||||
AccountDB = apps.get_model('accounts', 'AccountDB')
|
||||
ObjectDB = apps.get_model('objects', 'ObjectDB')
|
||||
|
||||
for object in ObjectDB.objects.all():
|
||||
account = object.db_account
|
||||
if account:
|
||||
account = AccountDB.objects.get(id=account.id)
|
||||
object.db_account = account
|
||||
object.save(update_fields=['db_account'])
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('objects', '0007_objectdb_db_account'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards)
|
||||
]
|
||||
36
evennia/objects/migrations/0009_remove_objectdb_db_player.py
Normal file
36
evennia/objects/migrations/0009_remove_objectdb_db_player.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-06 20:41
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, connection
|
||||
from django.db import OperationalError
|
||||
|
||||
|
||||
def _table_exists(db_cursor, tablename):
|
||||
"Returns bool if table exists or not"
|
||||
sql_check_exists = "SELECT * from %s;" % tablename
|
||||
try:
|
||||
db_cursor.execute(sql_check_exists)
|
||||
return True
|
||||
except OperationalError:
|
||||
return False
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('objects', '0008_auto_20170705_1736'),
|
||||
]
|
||||
|
||||
db_cursor = connection.cursor()
|
||||
|
||||
if not _table_exists(db_cursor, "objectdb_db_player"):
|
||||
# OBS - this is run BEFORE migrations are run!
|
||||
operations = []
|
||||
else:
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='objectdb',
|
||||
name='db_player',
|
||||
),
|
||||
]
|
||||
|
|
@ -18,6 +18,7 @@ from builtins import object
|
|||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.validators import validate_comma_separated_integer_list
|
||||
|
||||
from evennia.typeclasses.models import TypedObject
|
||||
from evennia.objects.manager import ObjectDBManager
|
||||
|
|
@ -140,16 +141,16 @@ class ObjectDB(TypedObject):
|
|||
|
||||
The ObjectDB adds the following properties:
|
||||
|
||||
- player - optional connected player (always together with sessid)
|
||||
- sessid - optional connection session id (always together with player)
|
||||
- account - optional connected account (always together with sessid)
|
||||
- sessid - optional connection session id (always together with account)
|
||||
- location - in-game location of object
|
||||
- home - safety location for object (handler)
|
||||
- scripts - scripts assigned to object (handler from typeclass)
|
||||
- cmdset - active cmdset on object (handler from typeclass)
|
||||
- aliases - aliases for this object (property)
|
||||
- nicks - nicknames for *other* things in Evennia (handler)
|
||||
- sessions - sessions connected to this object (see also player)
|
||||
- has_player - bool if an active player is currently connected
|
||||
- sessions - sessions connected to this object (see also account)
|
||||
- has_account - bool if an active account is currently connected
|
||||
- contents - other objects having this object as location
|
||||
- exits - exits from this object
|
||||
|
||||
|
|
@ -168,12 +169,14 @@ class ObjectDB(TypedObject):
|
|||
# self.key instead). The wrappers are created at the metaclass level and
|
||||
# will automatically save and cache the data more efficiently.
|
||||
|
||||
# If this is a character object, the player is connected here.
|
||||
db_player = models.ForeignKey("players.PlayerDB", null=True, verbose_name='player', on_delete=models.SET_NULL,
|
||||
help_text='a Player connected to this object, if any.')
|
||||
# the session id associated with this player, if any
|
||||
db_sessid = models.CommaSeparatedIntegerField(null=True, max_length=32, verbose_name="session id",
|
||||
help_text="csv list of session ids of connected Player, if any.")
|
||||
# If this is a character object, the account is connected here.
|
||||
db_account = models.ForeignKey("accounts.AccountDB", null=True, verbose_name='account', on_delete=models.SET_NULL,
|
||||
help_text='an Account connected to this object, if any.')
|
||||
|
||||
# the session id associated with this account, if any
|
||||
db_sessid = models.CharField(null=True, max_length=32, validators=[validate_comma_separated_integer_list],
|
||||
verbose_name="session id",
|
||||
help_text="csv list of session ids of connected Account, 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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""
|
||||
This module defines the basic `DefaultObject` and its children
|
||||
`DefaultCharacter`, `DefaultPlayer`, `DefaultRoom` and `DefaultExit`.
|
||||
`DefaultCharacter`, `DefaultAccount`, `DefaultRoom` and `DefaultExit`.
|
||||
These are the (default) starting points for all in-game visible
|
||||
entities.
|
||||
|
||||
|
|
@ -21,7 +21,8 @@ from evennia.commands.cmdsethandler import CmdSetHandler
|
|||
from evennia.commands import cmdhandler
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.utils import (variable_from_module, lazy_property,
|
||||
make_iter, to_unicode, calledby, is_iter)
|
||||
make_iter, to_unicode, is_iter)
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||
|
||||
|
|
@ -32,8 +33,6 @@ _AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.',
|
|||
# the sessid_max is based on the length of the db_sessid csv field (excluding commas)
|
||||
_SESSID_MAX = 16 if _MULTISESSION_MODE in (1, 3) else 1
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
||||
class ObjectSessionHandler(object):
|
||||
"""
|
||||
|
|
@ -206,9 +205,9 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
return ObjectSessionHandler(self)
|
||||
|
||||
@property
|
||||
def has_player(self):
|
||||
def has_account(self):
|
||||
"""
|
||||
Convenience property for checking if an active player is
|
||||
Convenience property for checking if an active account is
|
||||
currently connected to this object.
|
||||
|
||||
"""
|
||||
|
|
@ -217,11 +216,11 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
@property
|
||||
def is_superuser(self):
|
||||
"""
|
||||
Check if user has a player, and if so, if it is a superuser.
|
||||
Check if user has an account, and if so, if it is a superuser.
|
||||
|
||||
"""
|
||||
return self.db_player and self.db_player.is_superuser \
|
||||
and not self.db_player.attributes.get("_quell")
|
||||
return self.db_account and self.db_account.is_superuser \
|
||||
and not self.db_account.attributes.get("_quell")
|
||||
|
||||
def contents_get(self, exclude=None):
|
||||
"""
|
||||
|
|
@ -260,7 +259,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
Displays the name of the object in a viewer-aware manner.
|
||||
|
||||
Args:
|
||||
looker (TypedObject): The object or player that is looking
|
||||
looker (TypedObject): The object or account that is looking
|
||||
at/getting inforamtion for this object.
|
||||
|
||||
Returns:
|
||||
|
|
@ -276,7 +275,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
builders.
|
||||
|
||||
"""
|
||||
if self.locks.check_lockstring(looker, "perm(Builders)"):
|
||||
if self.locks.check_lockstring(looker, "perm(Builder)"):
|
||||
return "{}(#{})".format(self.name, self.id)
|
||||
return self.name
|
||||
|
||||
|
|
@ -350,7 +349,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
otherwise it will return a list of 0, 1 or more matches.
|
||||
|
||||
Notes:
|
||||
To find Players, use eg. `evennia.player_search`. If
|
||||
To find Accounts, use eg. `evennia.account_search`. If
|
||||
`quiet=False`, error messages will be handled by
|
||||
`settings.SEARCH_AT_RESULT` and echoed automatically (on
|
||||
error, return will be `None`). If `quiet=True`, the error
|
||||
|
|
@ -368,7 +367,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
if use_nicks:
|
||||
# do nick-replacement on search
|
||||
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "player"), include_player=True)
|
||||
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "account"), include_account=True)
|
||||
|
||||
if (global_search or (is_string and searchdata.startswith("#") and
|
||||
len(searchdata) > 1 and searchdata[1:].isdigit())):
|
||||
|
|
@ -406,19 +405,19 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
return _AT_SEARCH_RESULT(results, self, query=searchdata,
|
||||
nofound_string=nofound_string, multimatch_string=multimatch_string)
|
||||
|
||||
def search_player(self, searchdata, quiet=False):
|
||||
def search_account(self, searchdata, quiet=False):
|
||||
"""
|
||||
Simple shortcut wrapper to search for players, not characters.
|
||||
Simple shortcut wrapper to search for accounts, not characters.
|
||||
|
||||
Args:
|
||||
searchdata (str): Search criterion - the key or dbref of the player
|
||||
searchdata (str): Search criterion - the key or dbref of the account
|
||||
to search for. If this is "here" or "me", search
|
||||
for the player connected to this object.
|
||||
for the account connected to this object.
|
||||
quiet (bool): Returns the results as a list rather than
|
||||
echo eventual standard error messages. Default `False`.
|
||||
|
||||
Returns:
|
||||
result (Player, None or list): Just what is returned depends on
|
||||
result (Account, None or list): Just what is returned depends on
|
||||
the `quiet` setting:
|
||||
- `quiet=True`: No match or multumatch auto-echoes errors
|
||||
to self.msg, then returns `None`. The esults are passed
|
||||
|
|
@ -427,15 +426,15 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
unique match, this will be returned.
|
||||
- `quiet=True`: No automatic error messaging is done, and
|
||||
what is returned is always a list with 0, 1 or more
|
||||
matching Players.
|
||||
matching Accounts.
|
||||
|
||||
"""
|
||||
if isinstance(searchdata, basestring):
|
||||
# searchdata is a string; wrap some common self-references
|
||||
if searchdata.lower() in ("me", "self",):
|
||||
return [self.player] if quiet else self.player
|
||||
return [self.account] if quiet else self.account
|
||||
|
||||
results = self.player.__class__.objects.player_search(searchdata)
|
||||
results = self.account.__class__.objects.account_search(searchdata)
|
||||
|
||||
if quiet:
|
||||
return results
|
||||
|
|
@ -446,7 +445,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
Do something as this object. This is never called normally,
|
||||
it's only used when wanting specifically to let an object be
|
||||
the caller of a command. It makes use of nicks of eventual
|
||||
connected players as well.
|
||||
connected accounts as well.
|
||||
|
||||
Args:
|
||||
raw_string (string): Raw command input
|
||||
|
|
@ -474,7 +473,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
# nick replacement - we require full-word matching.
|
||||
# do text encoding conversion
|
||||
raw_string = to_unicode(raw_string)
|
||||
raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_player=True)
|
||||
raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_account=True)
|
||||
return cmdhandler.cmdhandler(self, raw_string, callertype="object", session=session, **kwargs)
|
||||
|
||||
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
|
||||
|
|
@ -755,7 +754,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
def clear_contents(self):
|
||||
"""
|
||||
Moves all objects (players/things) to their home location or
|
||||
Moves all objects (accounts/things) to their home location or
|
||||
to default home.
|
||||
"""
|
||||
# Gather up everything that thinks this is its location.
|
||||
|
|
@ -786,13 +785,13 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
logger.log_err(string % (obj.name, obj.dbid))
|
||||
return
|
||||
|
||||
if obj.has_player:
|
||||
if obj.has_account:
|
||||
if home:
|
||||
string = "Your current location has ceased to exist,"
|
||||
string += " moving you to %s(#%d)."
|
||||
obj.msg(_(string) % (home.name, home.dbid))
|
||||
else:
|
||||
# Famous last words: The player should never see this.
|
||||
# Famous last words: The account should never see this.
|
||||
string = "This place should not exist ... contact an admin."
|
||||
obj.msg(_(string))
|
||||
obj.move_to(home)
|
||||
|
|
@ -820,8 +819,8 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
"""
|
||||
key = self.key
|
||||
num = 1
|
||||
for _ in (obj for obj in self.location.contents
|
||||
if obj.key.startswith(key) and obj.key.lstrip(key).isdigit()):
|
||||
for inum in (obj for obj in self.location.contents
|
||||
if obj.key.startswith(key) and obj.key.lstrip(key).isdigit()):
|
||||
num += 1
|
||||
return "%s%03i" % (key, num)
|
||||
new_key = new_key or find_clone_key()
|
||||
|
|
@ -858,16 +857,16 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
self.delete_iter += 1
|
||||
|
||||
# See if we need to kick the player off.
|
||||
# See if we need to kick the account off.
|
||||
|
||||
for session in self.sessions.all():
|
||||
session.msg(_("Your character %s has been destroyed.") % self.key)
|
||||
# no need to disconnect, Player just jumps to OOC mode.
|
||||
# no need to disconnect, Account just jumps to OOC mode.
|
||||
# sever the connection (important!)
|
||||
if self.player:
|
||||
if self.account:
|
||||
for session in self.sessions.all():
|
||||
self.player.unpuppet_object(session)
|
||||
self.player = None
|
||||
self.account.unpuppet_object(session)
|
||||
self.account = None
|
||||
|
||||
for script in _ScriptDB.objects.get_all_scripts_on_obj(self):
|
||||
script.stop()
|
||||
|
|
@ -948,21 +947,20 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
self.save(update_fields=updates)
|
||||
|
||||
if cdict.get("permissions"):
|
||||
self.permissions.add(cdict["permissions"])
|
||||
self.permissions.batch_add(*cdict["permissions"])
|
||||
if cdict.get("locks"):
|
||||
self.locks.add(cdict["locks"])
|
||||
if cdict.get("aliases"):
|
||||
self.aliases.add(cdict["aliases"])
|
||||
self.aliases.batch_add(*cdict["aliases"])
|
||||
if cdict.get("location"):
|
||||
cdict["location"].at_object_receive(self, None)
|
||||
self.at_after_move(None)
|
||||
if cdict.get("tags"):
|
||||
# this should be a list of tags
|
||||
self.tags.add(cdict["tags"])
|
||||
self.tags.batch_add(*cdict["tags"])
|
||||
if cdict.get("attributes"):
|
||||
# this should be a dict of attrname:value
|
||||
keys, values = list(cdict["attributes"]), listvalues(cdict["attributes"])
|
||||
self.attributes.batch_add(keys, values)
|
||||
self.attributes.batch_add(*cdict["attributes"])
|
||||
if cdict.get("nattributes"):
|
||||
# this should be a dict of nattrname:value
|
||||
for key, value in cdict["nattributes"].items():
|
||||
|
|
@ -989,15 +987,15 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
# controller, for example)
|
||||
|
||||
self.locks.add(";".join([
|
||||
"control:perm(Immortals)", # edit locks/permissions, delete
|
||||
"examine:perm(Builders)", # examine properties
|
||||
"view:all()", # look at object (visibility)
|
||||
"edit:perm(Wizards)", # edit properties/attributes
|
||||
"delete:perm(Wizards)", # delete object
|
||||
"get:all()", # pick up object
|
||||
"call:true()", # allow to call commands on this object
|
||||
"tell:perm(Wizards)", # allow emits to this object
|
||||
"puppet:pperm(Immortals)"])) # lock down puppeting only to staff by default
|
||||
"control:perm(Developer)", # edit locks/permissions, delete
|
||||
"examine:perm(Builder)", # examine properties
|
||||
"view:all()", # look at object (visibility)
|
||||
"edit:perm(Admin)", # edit properties/attributes
|
||||
"delete:perm(Admin)", # delete object
|
||||
"get:all()", # pick up object
|
||||
"call:true()", # allow to call commands on this object
|
||||
"tell:perm(Admin)", # allow emits to this object
|
||||
"puppet:pperm(Developer)"])) # lock down puppeting only to staff by default
|
||||
|
||||
def basetype_posthook_setup(self):
|
||||
"""
|
||||
|
|
@ -1048,61 +1046,72 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
have no cmdsets.
|
||||
|
||||
Kwargs:
|
||||
caller (Session, Object or Player): The caller requesting
|
||||
caller (Session, Object or Account): The caller requesting
|
||||
this cmdset.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_pre_puppet(self, player, session=None):
|
||||
def at_pre_puppet(self, account, session=None, **kwargs):
|
||||
"""
|
||||
Called just before a Player connects to this object to puppet
|
||||
Called just before an Account connects to this object to puppet
|
||||
it.
|
||||
|
||||
Args:
|
||||
player (Player): This is the connecting player.
|
||||
account (Account): This is the connecting account.
|
||||
session (Session): Session controlling the connection.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_post_puppet(self):
|
||||
def at_post_puppet(self, **kwargs):
|
||||
"""
|
||||
Called just after puppeting has been completed and all
|
||||
Player<->Object links have been established.
|
||||
Account<->Object links have been established.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
Note:
|
||||
You can use `self.player` and `self.sessions.get()` to get
|
||||
player and sessions at this point; the last entry in the
|
||||
You can use `self.account` and `self.sessions.get()` to get
|
||||
account and sessions at this point; the last entry in the
|
||||
list from `self.sessions.get()` is the latest Session
|
||||
puppeting this Object.
|
||||
|
||||
"""
|
||||
self.player.db._last_puppet = self
|
||||
self.account.db._last_puppet = self
|
||||
|
||||
def at_pre_unpuppet(self):
|
||||
def at_pre_unpuppet(self, **kwargs):
|
||||
"""
|
||||
Called just before beginning to un-connect a puppeting from
|
||||
this Player.
|
||||
this Account.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
Note:
|
||||
You can use `self.player` and `self.sessions.get()` to get
|
||||
player and sessions at this point; the last entry in the
|
||||
You can use `self.account` and `self.sessions.get()` to get
|
||||
account and sessions at this point; the last entry in the
|
||||
list from `self.sessions.get()` is the latest Session
|
||||
puppeting this Object.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_post_unpuppet(self, player, session=None):
|
||||
def at_post_unpuppet(self, account, session=None, **kwargs):
|
||||
"""
|
||||
Called just after the Player successfully disconnected from
|
||||
Called just after the Account successfully disconnected from
|
||||
this object, severing all connections.
|
||||
|
||||
Args:
|
||||
player (Player): The player object that just disconnected
|
||||
account (Account): The account object that just disconnected
|
||||
from this object.
|
||||
session (Session): Session id controlling the connection that
|
||||
just disconnected.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
|
@ -1134,7 +1143,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
Args:
|
||||
result (bool): The outcome of the access call.
|
||||
accessing_obj (Object or Player): The entity trying to gain access.
|
||||
accessing_obj (Object or Account): The entity trying to gain access.
|
||||
access_type (str): The type of access that was requested.
|
||||
|
||||
Kwargs:
|
||||
|
|
@ -1146,13 +1155,15 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
# hooks called when moving the object
|
||||
|
||||
def at_before_move(self, destination):
|
||||
def at_before_move(self, destination, **kwargs):
|
||||
"""
|
||||
Called just before starting to move this object to
|
||||
destination.
|
||||
|
||||
Args:
|
||||
destination (Object): The object we are moving to
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
shouldmove (bool): If we should move or not.
|
||||
|
|
@ -1165,7 +1176,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
# return has_perm(self, destination, "can_move")
|
||||
return True
|
||||
|
||||
def announce_move_from(self, destination, msg=None, mapping=None):
|
||||
def announce_move_from(self, destination, msg=None, mapping=None, **kwargs):
|
||||
"""
|
||||
Called if the move is to be announced. This is
|
||||
called while we are still standing in the old
|
||||
|
|
@ -1175,6 +1186,8 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
destination (Object): The place we are going to.
|
||||
msg (str, optional): a replacement message.
|
||||
mapping (dict, optional): additional mapping objects.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
You can override this method and call its parent with a
|
||||
message to simply change the default message. In the string,
|
||||
|
|
@ -1206,7 +1219,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
location.msg_contents(string, exclude=(self, ), mapping=mapping)
|
||||
|
||||
def announce_move_to(self, source_location, msg=None, mapping=None):
|
||||
def announce_move_to(self, source_location, msg=None, mapping=None, **kwargs):
|
||||
"""
|
||||
Called after the move if the move was not quiet. At this point
|
||||
we are standing in the new location.
|
||||
|
|
@ -1215,19 +1228,22 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
source_location (Object): The place we came from
|
||||
msg (str, optional): the replacement message if location.
|
||||
mapping (dict, optional): additional mapping objects.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
You can override this method and call its parent with a
|
||||
message to simply change the default message. In the string,
|
||||
you can use the following as mappings (between braces):
|
||||
object: the object which is moving.
|
||||
exit: the exit from which the object is moving (if found).
|
||||
origin: the location of the object before the move.
|
||||
destination: the location of the object after moving.
|
||||
Notes:
|
||||
You can override this method and call its parent with a
|
||||
message to simply change the default message. In the string,
|
||||
you can use the following as mappings (between braces):
|
||||
object: the object which is moving.
|
||||
exit: the exit from which the object is moving (if found).
|
||||
origin: the location of the object before the move.
|
||||
destination: the location of the object after moving.
|
||||
|
||||
"""
|
||||
|
||||
if not source_location and self.location.has_player:
|
||||
# This was created from nowhere and added to a player's
|
||||
if not source_location and self.location.has_account:
|
||||
# This was created from nowhere and added to an account's
|
||||
# inventory; it's probably the result of a create command.
|
||||
string = "You now have %s in your possession." % self.get_display_name(self.location)
|
||||
self.location.msg(string)
|
||||
|
|
@ -1259,7 +1275,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
destination.msg_contents(string, exclude=(self, ), mapping=mapping)
|
||||
|
||||
def at_after_move(self, source_location):
|
||||
def at_after_move(self, source_location, **kwargs):
|
||||
"""
|
||||
Called after move has completed, regardless of quiet mode or
|
||||
not. Allows changes to the object due to the location it is
|
||||
|
|
@ -1267,22 +1283,26 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
Args:
|
||||
source_location (Object): Wwhere we came from. This may be `None`.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_object_leave(self, moved_obj, target_location):
|
||||
def at_object_leave(self, moved_obj, target_location, **kwargs):
|
||||
"""
|
||||
Called just before an object leaves from inside this object
|
||||
|
||||
Args:
|
||||
moved_obj (Object): The object leaving
|
||||
target_location (Object): Where `moved_obj` is going.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_object_receive(self, moved_obj, source_location):
|
||||
def at_object_receive(self, moved_obj, source_location, **kwargs):
|
||||
"""
|
||||
Called after an object has been moved into this object.
|
||||
|
||||
|
|
@ -1290,11 +1310,13 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
moved_obj (Object): The object moved into this one
|
||||
source_location (Object): Where `moved_object` came from.
|
||||
Note that this could be `None`.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_traverse(self, traversing_object, target_location):
|
||||
def at_traverse(self, traversing_object, target_location, **kwargs):
|
||||
"""
|
||||
This hook is responsible for handling the actual traversal,
|
||||
normally by calling
|
||||
|
|
@ -1307,11 +1329,13 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
Args:
|
||||
traversing_object (Object): Object traversing us.
|
||||
target_location (Object): Where target is going.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_after_traverse(self, traversing_object, source_location):
|
||||
def at_after_traverse(self, traversing_object, source_location, **kwargs):
|
||||
"""
|
||||
Called just after an object successfully used this object to
|
||||
traverse to another object (i.e. this object is a type of
|
||||
|
|
@ -1320,19 +1344,23 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
Args:
|
||||
traversing_object (Object): The object traversing us.
|
||||
source_location (Object): Where `traversing_object` came from.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
The target location should normally be available as `self.destination`.
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_failed_traverse(self, traversing_object):
|
||||
def at_failed_traverse(self, traversing_object, **kwargs):
|
||||
"""
|
||||
This is called if an object fails to traverse this object for
|
||||
some reason.
|
||||
|
||||
Args:
|
||||
traversing_object (Object): The object that failed traversing us.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
Using the default exits, this hook will not be called if an
|
||||
|
|
@ -1393,13 +1421,15 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
# hooks called by the default cmdset.
|
||||
|
||||
def return_appearance(self, looker):
|
||||
def return_appearance(self, looker, **kwargs):
|
||||
"""
|
||||
This formats a description. It is the hook a 'look' command
|
||||
should call.
|
||||
|
||||
Args:
|
||||
looker (Object): Object doing the looking.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
"""
|
||||
if not looker:
|
||||
return ""
|
||||
|
|
@ -1411,7 +1441,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
key = con.get_display_name(looker)
|
||||
if con.destination:
|
||||
exits.append(key)
|
||||
elif con.has_player:
|
||||
elif con.has_account:
|
||||
users.append("|c%s|n" % key)
|
||||
else:
|
||||
things.append(key)
|
||||
|
|
@ -1426,7 +1456,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
string += "\n|wYou see:|n " + ", ".join(users + things)
|
||||
return string
|
||||
|
||||
def at_look(self, target):
|
||||
def at_look(self, target, **kwargs):
|
||||
"""
|
||||
Called when this object performs a look. It allows to
|
||||
customize just what this means. It will not itself
|
||||
|
|
@ -1436,6 +1466,8 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
target (Object): The target being looked at. This is
|
||||
commonly an object or the current location. It will
|
||||
be checked for the "view" type access.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
lookstring (str): A ready-processed look string
|
||||
|
|
@ -1456,22 +1488,27 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
|
||||
return description
|
||||
|
||||
def at_desc(self, looker=None):
|
||||
def at_desc(self, looker=None, **kwargs):
|
||||
"""
|
||||
This is called whenever someone looks at this object.
|
||||
|
||||
looker (Object): The object requesting the description.
|
||||
Args:
|
||||
looker (Object, optional): The object requesting the description.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def at_get(self, getter):
|
||||
def at_get(self, getter, **kwargs):
|
||||
"""
|
||||
Called by the default `get` command when this object has been
|
||||
picked up.
|
||||
|
||||
Args:
|
||||
getter (Object): The object getting this object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
This hook cannot stop the pickup from happening. Use
|
||||
|
|
@ -1480,7 +1517,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_give(self, giver, getter):
|
||||
def at_give(self, giver, getter, **kwargs):
|
||||
"""
|
||||
Called by the default `give` command when this object has been
|
||||
given.
|
||||
|
|
@ -1488,6 +1525,8 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
Args:
|
||||
giver (Object): The object giving this object.
|
||||
getter (Object): The object getting this object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
This hook cannot stop the give from happening. Use
|
||||
|
|
@ -1496,13 +1535,15 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_drop(self, dropper):
|
||||
def at_drop(self, dropper, **kwargs):
|
||||
"""
|
||||
Called by the default `drop` command when this object has been
|
||||
dropped.
|
||||
|
||||
Args:
|
||||
dropper (Object): The object which just dropped this object.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
This hook cannot stop the drop from happening. Use
|
||||
|
|
@ -1511,149 +1552,103 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_before_say(self, speech):
|
||||
def at_before_say(self, message, **kwargs):
|
||||
"""
|
||||
Before the object says something.
|
||||
|
||||
This hook is called by the 'say' command on the object itself
|
||||
(probably a character). It is called before the actual say,
|
||||
and can be used to control the content of the text to be said,
|
||||
prevent saying altogether or perform some alternative checks.
|
||||
This hook should return the modified speech. If this return
|
||||
value is empty (like "" or None), the command is aborted.
|
||||
This hook is by default used by the 'say' and 'whisper'
|
||||
commands as used by this command it is called before the text
|
||||
is said/whispered and can be used to customize the outgoing
|
||||
text from the object. Returning `None` aborts the command.
|
||||
|
||||
Args:
|
||||
speech (str): the text to be said by self.
|
||||
message (str): The suggested say/whisper text spoken by self.
|
||||
Kwargs:
|
||||
whisper (bool): If True, this is a whisper rather than
|
||||
a say. This is sent by the whisper command by default.
|
||||
Other verbal commands could use this hook in similar
|
||||
ways.
|
||||
receiver (Object): If set, this is a target for the say/whisper.
|
||||
|
||||
Returns:
|
||||
speech (str): the text to be said (can be modified).
|
||||
message (str): The (possibly modified) text to be spoken.
|
||||
|
||||
"""
|
||||
return speech
|
||||
return message
|
||||
|
||||
def at_after_say(self, speech, msg_self=None, msg_location=None,
|
||||
mapping=None):
|
||||
def at_say(self, message, msg_self=None, msg_location=None,
|
||||
receiver=None, msg_receiver=None, mapping=None, **kwargs):
|
||||
"""
|
||||
Display the actual say of self.
|
||||
Display the actual say (or whisper) of self.
|
||||
|
||||
This hook should display the actual say of the object in its
|
||||
This hook should display the actual say/whisper of the object in its
|
||||
location. It should both alert the object (self) and its
|
||||
location that some text is spoken. The overriding of messages or
|
||||
`mapping` allows for simple customization of the hook without
|
||||
re-writing it completely.
|
||||
|
||||
Args:
|
||||
speech (str): the text to be said by self.
|
||||
msg_self (str, optional): the replacement message to say to self.
|
||||
msg_location (str, optional): the replacement message to say
|
||||
to the location.
|
||||
message (str): The text to be conveyed by self.
|
||||
msg_self (str, optional): The message to echo to self.
|
||||
msg_location (str, optional): The message to echo to self's location.
|
||||
receiver (Object, optional): An eventual receiver of the message
|
||||
(by default only used by whispers).
|
||||
msg_receiver(str, optional): Specific message for receiver only.
|
||||
mapping (dict, optional): Additional mapping in messages.
|
||||
Kwargs:
|
||||
whisper (bool): If this is a whisper rather than a say. Kwargs
|
||||
can be used by other verbal commands in a similar way.
|
||||
|
||||
Both `msg_self` and `msg_location` should contain references
|
||||
to other objects between braces, the way `locaiton.msg_contents`
|
||||
would allow. For instance:
|
||||
msg_self = 'You say: "{speech}"'
|
||||
msg_location = '{object} says: "{speech}"'
|
||||
Notes:
|
||||
|
||||
The following mappings can be used in both messages:
|
||||
object: the object speaking.
|
||||
location: the location where object is.
|
||||
speech: the text spoken by self.
|
||||
Messages can contain {} markers, which must
|
||||
If used, `msg_self`, `msg_receiver` and `msg_location` should contain
|
||||
references to other objects between braces, the way `location.msg_contents`
|
||||
would allow. For instance:
|
||||
msg_self = 'You say: "{speech}"'
|
||||
msg_location = '{object} says: "{speech}"'
|
||||
msg_receiver = '{object} whispers: "{speech}"'
|
||||
|
||||
You can use additional mappings if you want to add other
|
||||
information in your messages.
|
||||
The following mappings can be used in both messages:
|
||||
object: the object speaking.
|
||||
location: the location where object is.
|
||||
speech: the text spoken by self.
|
||||
|
||||
You can use additional mappings if you want to add other
|
||||
information in your messages.
|
||||
|
||||
"""
|
||||
if self.location is None:
|
||||
self.msg("You can't utter a sound in the void.")
|
||||
return
|
||||
if kwargs.get("whisper", False):
|
||||
# whisper mode
|
||||
msg_self = msg_self or 'You whisper to {receiver}, "{speech}"|n'
|
||||
msg_receiver = msg_receiver or '{object} whispers: "{speech}"|n'
|
||||
msg_location = None
|
||||
else:
|
||||
msg_self = msg_self or 'You say, "{speech}"|n'
|
||||
msg_receiver = None
|
||||
msg_location = msg_location or '{object} says, "{speech}"|n'
|
||||
|
||||
msg_self = msg_self or 'You say, "{speech}"|n'
|
||||
msg_location = msg_location or '{object} says, "{speech}"|n'
|
||||
mapping = mapping or {}
|
||||
mapping.update({
|
||||
"object": self,
|
||||
"location": self.location,
|
||||
"speech": speech,
|
||||
})
|
||||
self_mapping = {k: v.get_display_name(self) if hasattr(
|
||||
v, "get_display_name") else str(v) for k, v in mapping.items()}
|
||||
self.msg(msg_self.format(**self_mapping))
|
||||
self.location.msg_contents(msg_location, exclude=(self, ),
|
||||
mapping=mapping)
|
||||
"speech": message,
|
||||
"receiver": receiver
|
||||
})
|
||||
|
||||
def at_before_whisper(self, receiver, speech):
|
||||
"""
|
||||
Before the object whispers something to receiver.
|
||||
if msg_self:
|
||||
self_mapping = {k: v.get_display_name(self) if hasattr(
|
||||
v, "get_display_name") else str(v) for k, v in mapping.items()}
|
||||
self.msg(msg_self.format(**self_mapping))
|
||||
|
||||
This hook is called by the 'whisper' command on the object itself
|
||||
(probably a character). It is called before the actual whisper,
|
||||
and can be used to control the content of the text to be whispered,
|
||||
prevent whispering altogether or perform some alternative checks.
|
||||
This hook should return the modified speech. If this return
|
||||
value is empty (like "" or None), the command is aborted.
|
||||
|
||||
Args:
|
||||
receiver (Object): the object to whisper to.
|
||||
speech (str): the text to be whispered by self.
|
||||
|
||||
Returns:
|
||||
speech (str): the text to be whispered (can be modified).
|
||||
|
||||
"""
|
||||
return speech
|
||||
|
||||
def at_after_whisper(self, receiver, speech, msg_self=None,
|
||||
msg_receiver=None, mapping=None):
|
||||
"""
|
||||
Display the actual whisper of self.
|
||||
|
||||
This hook should display the actual whisper of the object to
|
||||
receiver. It should both alert the object (self) and the
|
||||
receiver. You can also notify the location if you want to,
|
||||
to indicate to others that a message was whispered but you
|
||||
can't hear it. The overriding of messages or
|
||||
`mapping` allows for simple customization of the hook without
|
||||
re-writing it completely.
|
||||
|
||||
Args:
|
||||
receiver (Objecvt): the object to whisper to.
|
||||
speech (str): the text to be said by self.
|
||||
msg_self (str, optional): the replacement message to say to self.
|
||||
msg_receiver (str, optional): the replacement message to say
|
||||
to receiver.
|
||||
mapping (dict, optional): Additional mapping in messages.
|
||||
|
||||
Both `msg_self` and `msg_receiver` should contain references
|
||||
to other objects between braces, the way `locaiton.msg_contents`
|
||||
would allow. For instance:
|
||||
msg_self = 'You whisper to {receiver}, "{speech}"|n'
|
||||
msg_receiver = '{object} whispers: "{speech}"|n'
|
||||
|
||||
The following mappings can be used in both messages:
|
||||
object: the object whispering.
|
||||
receiver: the object whispered to.
|
||||
speech: the text spoken by self.
|
||||
|
||||
You can use additional mappings if you want to add other
|
||||
information in your messages.
|
||||
|
||||
"""
|
||||
msg_self = msg_self or 'You whisper to {receiver}, "{speech}"|n'
|
||||
msg_receiver = msg_receiver or '{object} whispers: "{speech}"|n'
|
||||
mapping = mapping or {}
|
||||
mapping.update({
|
||||
"object": self,
|
||||
"receiver": receiver,
|
||||
"speech": speech,
|
||||
})
|
||||
self_mapping = {k: v.get_display_name(self) if hasattr(
|
||||
v, "get_display_name") else str(v) for k, v in mapping.items()}
|
||||
receiver_mapping = {k: v.get_display_name(receiver) if hasattr(
|
||||
v, "get_display_name") else str(v) for k, v in mapping.items()}
|
||||
self.msg(msg_self.format(**self_mapping))
|
||||
receiver.msg(msg_receiver.format(**receiver_mapping))
|
||||
if receiver and msg_receiver:
|
||||
receiver_mapping = {k: v.get_display_name(receiver) if hasattr(
|
||||
v, "get_display_name") else str(v) for k, v in mapping.items()}
|
||||
receiver.msg(msg_receiver.format(**receiver_mapping))
|
||||
|
||||
if self.location and msg_location:
|
||||
self.location.msg_contents(msg_location, exclude=(self, ),
|
||||
mapping=mapping)
|
||||
|
||||
|
||||
#
|
||||
|
|
@ -1663,7 +1658,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
|
|||
class DefaultCharacter(DefaultObject):
|
||||
"""
|
||||
This implements an Object puppeted by a Session - that is,
|
||||
a character avatar controlled by a player.
|
||||
a character avatar controlled by an account.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -1683,7 +1678,7 @@ class DefaultCharacter(DefaultObject):
|
|||
# add the default cmdset
|
||||
self.cmdset.add_default(settings.CMDSET_CHARACTER, permanent=True)
|
||||
|
||||
def at_after_move(self, source_location):
|
||||
def at_after_move(self, source_location, **kwargs):
|
||||
"""
|
||||
We make sure to look around after a move.
|
||||
|
||||
|
|
@ -1691,11 +1686,11 @@ class DefaultCharacter(DefaultObject):
|
|||
if self.location.access(self, "view"):
|
||||
self.msg(self.at_look(self.location))
|
||||
|
||||
def at_pre_puppet(self, player, session=None):
|
||||
def at_pre_puppet(self, account, session=None, **kwargs):
|
||||
"""
|
||||
Return the character from storage in None location in `at_post_unpuppet`.
|
||||
Args:
|
||||
player (Player): This is the connecting player.
|
||||
account (Account): This is the connecting account.
|
||||
session (Session): Session controlling the connection.
|
||||
"""
|
||||
if self.location is None: # Make sure character's location is never None before being puppeted.
|
||||
|
|
@ -1705,16 +1700,19 @@ class DefaultCharacter(DefaultObject):
|
|||
if self.location: # If the character is verified to be somewhere,
|
||||
self.db.prelogout_location = self.location # save location again to be sure.
|
||||
else:
|
||||
player.msg("|r%s has no location and no home is set.|n" % self, session=session) # Note to set home.
|
||||
account.msg("|r%s has no location and no home is set.|n" % self, session=session) # Note to set home.
|
||||
|
||||
def at_post_puppet(self):
|
||||
def at_post_puppet(self, **kwargs):
|
||||
"""
|
||||
Called just after puppeting has been completed and all
|
||||
Player<->Object links have been established.
|
||||
Account<->Object links have been established.
|
||||
|
||||
Args:
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
Note:
|
||||
You can use `self.player` and `self.sessions.get()` to get
|
||||
player and sessions at this point; the last entry in the
|
||||
You can use `self.account` and `self.sessions.get()` to get
|
||||
account and sessions at this point; the last entry in the
|
||||
list from `self.sessions.get()` is the latest Session
|
||||
puppeting this Object.
|
||||
|
||||
|
|
@ -1726,17 +1724,19 @@ class DefaultCharacter(DefaultObject):
|
|||
obj.msg("%s has entered the game." % self.get_display_name(obj), from_obj=from_obj)
|
||||
self.location.for_contents(message, exclude=[self], from_obj=self)
|
||||
|
||||
def at_post_unpuppet(self, player, session=None):
|
||||
def at_post_unpuppet(self, account, session=None, **kwargs):
|
||||
"""
|
||||
We stove away the character when the player goes ooc/logs off,
|
||||
We stove away the character when the account goes ooc/logs off,
|
||||
otherwise the character object will remain in the room also
|
||||
after the player logged off ("headless", so to say).
|
||||
after the account logged off ("headless", so to say).
|
||||
|
||||
Args:
|
||||
player (Player): The player object that just disconnected
|
||||
account (Account): The account object that just disconnected
|
||||
from this object.
|
||||
session (Session): Session controlling the connection that
|
||||
just disconnected.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
"""
|
||||
if not self.sessions.count():
|
||||
# only remove this char from grid if no sessions control it anymore.
|
||||
|
|
@ -1826,6 +1826,8 @@ class ExitCommand(command.Command):
|
|||
|
||||
Args:
|
||||
caller (Object): The object (usually a character) that entered an ambiguous command.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Returns:
|
||||
A string with identifying information to disambiguate the command, conventionally with a preceding space.
|
||||
|
|
@ -1862,7 +1864,7 @@ class DefaultExit(DefaultObject):
|
|||
Helper function for creating an exit command set + command.
|
||||
|
||||
The command of this cmdset has the same name as the Exit
|
||||
object and allows the exit to react when the player enter the
|
||||
object and allows the exit to react when the account enter the
|
||||
exit's name, triggering the movement between rooms.
|
||||
|
||||
Args:
|
||||
|
|
@ -1936,7 +1938,7 @@ class DefaultExit(DefaultObject):
|
|||
"""
|
||||
self.cmdset.remove_default()
|
||||
|
||||
def at_traverse(self, traversing_object, target_location):
|
||||
def at_traverse(self, traversing_object, target_location, **kwargs):
|
||||
"""
|
||||
This implements the actual traversal. The traverse lock has
|
||||
already been checked (in the Exit command) at this point.
|
||||
|
|
@ -1944,6 +1946,8 @@ class DefaultExit(DefaultObject):
|
|||
Args:
|
||||
traversing_object (Object): Object traversing us.
|
||||
target_location (Object): Where target is going.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
source_location = traversing_object.location
|
||||
|
|
@ -1957,12 +1961,14 @@ class DefaultExit(DefaultObject):
|
|||
# No shorthand error message. Call hook.
|
||||
self.at_failed_traverse(traversing_object)
|
||||
|
||||
def at_failed_traverse(self, traversing_object):
|
||||
def at_failed_traverse(self, traversing_object, **kwargs):
|
||||
"""
|
||||
Overloads the default hook to implement a simple default error message.
|
||||
|
||||
Args:
|
||||
traversing_object (Object): The object that failed traversing us.
|
||||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
Using the default exits, this hook will not be called if an
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
"""
|
||||
This sub-package defines the out-of-character entities known as
|
||||
Players. These are equivalent to 'accounts' and can puppet one or
|
||||
more Objects depending on settings. A Player has no in-game existence.
|
||||
|
||||
"""
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
"""
|
||||
This sub-package holds the Scripts system. Scripts are database
|
||||
entities that can store data both in connection to Objects and Players
|
||||
entities that can store data both in connection to Objects and Accounts
|
||||
or globally. They may also have a timer-component to execute various
|
||||
timed effects.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ The custom manager for Scripts.
|
|||
|
||||
from django.db.models import Q
|
||||
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
||||
from evennia.typeclasses.managers import returns_typeclass_list
|
||||
from evennia.utils.utils import make_iter
|
||||
__all__ = ("ScriptManager",)
|
||||
_GA = object.__getattribute__
|
||||
|
|
@ -35,7 +34,6 @@ class ScriptDBManager(TypedObjectManager):
|
|||
copy_script
|
||||
|
||||
"""
|
||||
@returns_typeclass_list
|
||||
def get_all_scripts_on_obj(self, obj, key=None):
|
||||
"""
|
||||
Find all Scripts related to a particular object.
|
||||
|
|
@ -51,24 +49,23 @@ class ScriptDBManager(TypedObjectManager):
|
|||
"""
|
||||
if not obj:
|
||||
return []
|
||||
player = _GA(_GA(obj, "__dbclass__"), "__name__") == "PlayerDB"
|
||||
account = _GA(_GA(obj, "__dbclass__"), "__name__") == "AccountDB"
|
||||
if key:
|
||||
dbref = self.dbref(key)
|
||||
if dbref or dbref == 0:
|
||||
if player:
|
||||
return self.filter(db_player=obj, id=dbref)
|
||||
if account:
|
||||
return self.filter(db_account=obj, id=dbref)
|
||||
else:
|
||||
return self.filter(db_obj=obj, id=dbref)
|
||||
elif player:
|
||||
return self.filter(db_player=obj, db_key=key)
|
||||
elif account:
|
||||
return self.filter(db_account=obj, db_key=key)
|
||||
else:
|
||||
return self.filter(db_obj=obj, db_key=key)
|
||||
elif player:
|
||||
return self.filter(db_player=obj)
|
||||
elif account:
|
||||
return self.filter(db_account=obj)
|
||||
else:
|
||||
return self.filter(db_obj=obj)
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_all_scripts(self, key=None):
|
||||
"""
|
||||
Get all scripts in the database.
|
||||
|
|
@ -200,7 +197,7 @@ class ScriptDBManager(TypedObjectManager):
|
|||
elif obj:
|
||||
scripts = self.get_all_scripts_on_obj(obj, key=key)
|
||||
else:
|
||||
scripts = self.get_all_scripts(key=key) #self.model.get_all_cached_instances()
|
||||
scripts = self.get_all_scripts(key=key)
|
||||
|
||||
if not scripts:
|
||||
# no scripts available to validate
|
||||
|
|
@ -216,7 +213,6 @@ class ScriptDBManager(TypedObjectManager):
|
|||
VALIDATE_ITERATION -= 1
|
||||
return nr_started, nr_stopped
|
||||
|
||||
@returns_typeclass_list
|
||||
def search_script(self, ostring, obj=None, only_timed=False):
|
||||
"""
|
||||
Search for a particular script.
|
||||
|
|
@ -236,8 +232,8 @@ class ScriptDBManager(TypedObjectManager):
|
|||
if dbref or dbref == 0:
|
||||
# this is a dbref, try to find the script directly
|
||||
dbref_match = self.dbref_search(dbref)
|
||||
if dbref_match and not ((obj and obj != dbref_match.obj)
|
||||
or (only_timed and dbref_match.interval)):
|
||||
if dbref_match and not ((obj and obj != dbref_match.obj) or
|
||||
(only_timed and dbref_match.interval)):
|
||||
return [dbref_match]
|
||||
|
||||
# not a dbref; normal search
|
||||
|
|
@ -273,5 +269,6 @@ class ScriptDBManager(TypedObjectManager):
|
|||
locks=new_locks, autostart=True)
|
||||
return new_script
|
||||
|
||||
|
||||
class ScriptManager(ScriptDBManager, TypeclassManager):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class Migration(migrations.Migration):
|
|||
('db_is_active', models.BooleanField(default=False, verbose_name=b'script active')),
|
||||
('db_attributes', models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute', null=True)),
|
||||
('db_obj', models.ForeignKey(blank=True, to='objects.ObjectDB', help_text=b'the object to store this script on, if not a global script.', null=True, verbose_name=b'scripted object')),
|
||||
('db_player', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, help_text=b'the player to store this script on (should not be set if obj is set)', null=True, verbose_name=b'scripted player')),
|
||||
('db_account', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, help_text=b'the account to store this script on (should not be set if obj is set)', null=True, verbose_name=b'scripted account')),
|
||||
('db_tags', models.ManyToManyField(help_text=b'tags on this object. Tags are simple string markers to identify, group and alias objects.', to='typeclasses.Tag', null=True)),
|
||||
],
|
||||
options={
|
||||
|
|
|
|||
25
evennia/scripts/migrations/0008_auto_20170606_1731.py
Normal file
25
evennia/scripts/migrations/0008_auto_20170606_1731.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-06 17:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0007_auto_20150403_2339'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='scriptdb',
|
||||
name='db_attributes',
|
||||
field=models.ManyToManyField(help_text=b'attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).', to='typeclasses.Attribute'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='scriptdb',
|
||||
name='db_tags',
|
||||
field=models.ManyToManyField(help_text=b'tags on this object. Tags are simple string markers to identify, group and alias objects.', to='typeclasses.Tag'),
|
||||
),
|
||||
]
|
||||
22
evennia/scripts/migrations/0009_scriptdb_db_account.py
Normal file
22
evennia/scripts/migrations/0009_scriptdb_db_account.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-05 17:27
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0007_copy_player_to_account'),
|
||||
('scripts', '0008_auto_20170606_1731'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='scriptdb',
|
||||
name='db_account',
|
||||
field=models.ForeignKey(blank=True, help_text=b'the account to store this script on (should not be set if db_obj is set)', null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.AccountDB', verbose_name=b'scripted account'),
|
||||
),
|
||||
]
|
||||
33
evennia/scripts/migrations/0010_auto_20170705_1736.py
Normal file
33
evennia/scripts/migrations/0010_auto_20170705_1736.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-07-05 17:36
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
|
||||
try:
|
||||
apps.get_model('accounts', 'AccountDB')
|
||||
except LookupError:
|
||||
return
|
||||
AccountDB = apps.get_model('accounts', 'AccountDB')
|
||||
ScriptDB = apps.get_model('scripts', 'ScriptDB')
|
||||
|
||||
for script in ScriptDB.objects.all():
|
||||
account = script.db_account
|
||||
if account:
|
||||
account = AccountDB.objects.get(id=account.id)
|
||||
script.db_account = account
|
||||
script.save(update_fields=['db_account'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0009_scriptdb_db_account'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards)
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue