mirror of
https://github.com/evennia/evennia.git
synced 2026-04-05 15:37:17 +02:00
OBS: You need to resync your database! The Nickname system is now a separate database model with the result that also channel nicks are more robust. Also nickname replacement has been adjusted to fix some exceptional circumstances. Fixed a host of issues in the channel and nick handlers and adjoining commands that caused the channel-syscommands to fail in some situations. Resolves issue131. Resolves issue 132. Resolves issue 134.
This commit is contained in:
parent
7ebcefae2e
commit
2bdaf034c8
17 changed files with 298 additions and 305 deletions
|
|
@ -109,8 +109,9 @@ def get_and_merge_cmdsets(caller):
|
|||
exit_cmdset = EXITHANDLER.get_cmdset(caller)
|
||||
location = caller.location
|
||||
if location and not caller_cmdset.no_objs:
|
||||
# Gather all cmdsets stored on objects in the room.
|
||||
local_objlist = location.contents
|
||||
# Gather all cmdsets stored on objects in the room and
|
||||
# also in the caller's inventory
|
||||
local_objlist = location.contents + caller.contents
|
||||
local_objects_cmdsets = [obj.cmdset.current
|
||||
for obj in local_objlist
|
||||
if obj.cmdset.outside_access]
|
||||
|
|
@ -154,7 +155,7 @@ def match_command(cmd_candidates, cmdset, logged_caller=None):
|
|||
# Searching possible command matches in the given cmdset
|
||||
matches = []
|
||||
prev_found_cmds = [] # to avoid aliases clashing with themselves
|
||||
for cmd_candidate in cmd_candidates:
|
||||
for cmd_candidate in cmd_candidates:
|
||||
cmdmatches = list(set([cmd for cmd in cmdset
|
||||
if cmd == cmd_candidate.cmdname and
|
||||
cmd not in prev_found_cmds]))
|
||||
|
|
|
|||
|
|
@ -81,8 +81,7 @@ class DefaultCmdSet(CmdSet):
|
|||
# Comm commands
|
||||
self.add(comms.CmdAddCom())
|
||||
self.add(comms.CmdDelCom())
|
||||
self.add(comms.CmdComlist())
|
||||
self.add(comms.CmdClist())
|
||||
self.add(comms.CmdChannels())
|
||||
self.add(comms.CmdCdestroy())
|
||||
self.add(comms.CmdChannelCreate())
|
||||
self.add(comms.CmdCdesc())
|
||||
|
|
|
|||
|
|
@ -3,38 +3,43 @@ Comsys command module.
|
|||
"""
|
||||
|
||||
from src.comms.models import Channel, Msg, ChannelConnection
|
||||
from src.comms.channelhandler import CHANNELHANDLER
|
||||
from src.utils import create, utils
|
||||
from src.permissions.permissions import has_perm
|
||||
from src.commands.default.muxcommand import MuxCommand
|
||||
|
||||
def find_channel(caller, channelname):
|
||||
def find_channel(caller, channelname, silent=False):
|
||||
"""
|
||||
Helper function for searching for a single channel with
|
||||
some error handling.
|
||||
"""
|
||||
channels = Channel.objects.channel_search(channelname)
|
||||
if not channels:
|
||||
caller.msg("Channel '%s' not found." % channelname)
|
||||
if not silent:
|
||||
caller.msg("Channel '%s' not found." % channelname)
|
||||
return None
|
||||
elif len(channels) > 1:
|
||||
matches = ", ".join(["%s(%s)" % (chan.key, chan.id) for chan in channels])
|
||||
caller.msg("Multiple channels match (be more specific): \n%s" % matches)
|
||||
if not silent:
|
||||
caller.msg("Multiple channels match (be more specific): \n%s" % matches)
|
||||
return None
|
||||
return channels[0]
|
||||
|
||||
class CmdAddCom(MuxCommand):
|
||||
"""
|
||||
addcom - join a channel with alias
|
||||
addcom - subscribe to a channel with optional alias
|
||||
|
||||
Usage:
|
||||
addcom [alias=] <channel>
|
||||
|
||||
Allows adding an alias for a channel to make is easier and
|
||||
faster to use. Subsequent calls of this command can
|
||||
be used to add multiple aliases.
|
||||
Joins a given channel. If alias is given, this will allow you to
|
||||
refer to the channel by this alias rather than the full channel
|
||||
name. Subsequent calls of this command can be used to add multiple
|
||||
aliases to an already joined channel.
|
||||
"""
|
||||
|
||||
key = "addcom"
|
||||
aliases = ["aliaschan","chanalias"]
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
|
|
@ -78,9 +83,7 @@ class CmdAddCom(MuxCommand):
|
|||
|
||||
if alias:
|
||||
# create a nick and add it to the caller.
|
||||
nicks = caller.nicks
|
||||
nicks[alias.strip()] = channel.key
|
||||
caller.nicks = nicks # nicks auto-save to database.
|
||||
caller.nickhandler(alias, channel.key, nick_type="channel")
|
||||
string += "You can now refer to the channel %s with the alias '%s'."
|
||||
caller.msg(string % (channel.key, alias))
|
||||
else:
|
||||
|
|
@ -90,106 +93,55 @@ class CmdAddCom(MuxCommand):
|
|||
|
||||
class CmdDelCom(MuxCommand):
|
||||
"""
|
||||
delcom - remove a channel alias
|
||||
delcom - unsubscribe from channel or remove channel alias
|
||||
|
||||
Usage:
|
||||
delcom <alias>
|
||||
delcom <alias or channel>
|
||||
|
||||
Removes the specified alias to a channel. If this is the last alias,
|
||||
the user is effectively removed from the channel.
|
||||
If the full channel name is given, unsubscribe from the
|
||||
channel. If an alias is given, remove the alias but don't
|
||||
unsubscribe.
|
||||
"""
|
||||
|
||||
key = "delcom"
|
||||
aliases = ["delaliaschan, delchanalias"]
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
"Implementing the command. "
|
||||
|
||||
caller = self.caller
|
||||
player = caller.player
|
||||
|
||||
if not self.args:
|
||||
caller.msg("Usage: delcom <alias>")
|
||||
caller.msg("Usage: delcom <alias or channel>")
|
||||
return
|
||||
|
||||
#find all the nicks defining this channel
|
||||
searchnick = self.args.lower()
|
||||
nicks = caller.nicks
|
||||
channicks = [nick for nick in nicks.keys()
|
||||
if nick == searchnick]
|
||||
if not channicks:
|
||||
caller.msg("You don't have any such alias defined.")
|
||||
return
|
||||
#if there are possible nick matches, look if they match a channel.
|
||||
channel = None
|
||||
for nick in channicks:
|
||||
channel = find_channel(caller, nicks[nick])
|
||||
if channel:
|
||||
break
|
||||
if not channel:
|
||||
caller.msg("No channel with alias '%s' found." % searchnick)
|
||||
return
|
||||
player = caller.player
|
||||
ostring = self.args.lower()
|
||||
|
||||
if not channel.has_connection(player):
|
||||
caller.msg("You are not on that channel.")
|
||||
channel = find_channel(caller, ostring, silent=True)
|
||||
if channel:
|
||||
# we have given a channel name - unsubscribe
|
||||
if not channel.has_connection(player):
|
||||
caller.msg("You are listening to that channel.")
|
||||
return
|
||||
chkey = channel.key.lower()
|
||||
# find all nicks linked to this channel and delete them
|
||||
for nick in [nick for nick in caller.nicks
|
||||
if nick.db_type == "channel" and nick.db_real.lower() == chkey]:
|
||||
nick.delete()
|
||||
channel.disconnect_from(player)
|
||||
caller.msg("You stop listening to channel '%s'. Eventual aliases were removed." % channel.key)
|
||||
return
|
||||
else:
|
||||
if len(channicks) > 1:
|
||||
del nicks[searchnick]
|
||||
caller.msg("Your alias '%s' for channel %s was cleared." % (searchnick,
|
||||
channel.key))
|
||||
# we are removing a channel nick
|
||||
channame = caller.nickhandler(ostring, nick_type="channel")
|
||||
channel = find_channel(caller, channame, silent=True)
|
||||
if not channel:
|
||||
caller.msg("No channel with alias '%s' was found." % ostring)
|
||||
else:
|
||||
del nicks[searchnick]
|
||||
channel.disconnect_from(player)
|
||||
caller.msg("You stop listening to channel '%s'." % channel.key)
|
||||
# have to save nicks back too
|
||||
caller.nicks = nicks
|
||||
|
||||
class CmdComlist(MuxCommand):
|
||||
"""
|
||||
comlist - list channel memberships
|
||||
|
||||
Usage:
|
||||
comlist
|
||||
|
||||
Lists the channels a user is subscribed to.
|
||||
"""
|
||||
|
||||
key = "comlist"
|
||||
aliases = ["channels"]
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
"Implement the command"
|
||||
|
||||
|
||||
caller = self.caller
|
||||
player = caller.player
|
||||
|
||||
connections = ChannelConnection.objects.get_all_player_connections(player)
|
||||
|
||||
if not connections:
|
||||
caller.msg("You don't listen to any channels.")
|
||||
return
|
||||
|
||||
# get aliases:
|
||||
nicks = caller.nicks
|
||||
channicks = {}
|
||||
for connection in connections:
|
||||
channame = connection.channel.key.lower()
|
||||
channicks[channame] = ", ".join([nick for nick in nicks
|
||||
if nicks[nick].lower() == channame])
|
||||
caller.nickhandler(ostring, nick_type="channel", delete=True)
|
||||
caller.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key))
|
||||
|
||||
string = "Your subscribed channels (use @clist for full chan list)\n"
|
||||
string += "** Alias Channel Status\n"
|
||||
|
||||
for connection in connections:
|
||||
string += " %s%s %-15.14s%-22.15s\n" % ('-', '-',
|
||||
channicks[connection.channel.key.lower()],
|
||||
connection.channel.key)
|
||||
string = string[:-1]
|
||||
caller.msg(string)
|
||||
|
||||
|
||||
# def cmd_allcom(command):
|
||||
# """
|
||||
# allcom - operate on all channels
|
||||
|
|
@ -282,43 +234,74 @@ class CmdComlist(MuxCommand):
|
|||
## GLOBAL_CMD_TABLE.add_self("clearcom", cmd_clearcom)
|
||||
|
||||
|
||||
class CmdClist(MuxCommand):
|
||||
class CmdChannels(MuxCommand):
|
||||
"""
|
||||
@clist
|
||||
|
||||
Usage:
|
||||
@channels
|
||||
@clist
|
||||
list channels
|
||||
all channels
|
||||
comlist
|
||||
|
||||
Lists all available channels in the game.
|
||||
Lists all available channels available to you, wether you listen to them or not.
|
||||
Use 'comlist" to only view your current channel subscriptions.
|
||||
"""
|
||||
key = "@clist"
|
||||
aliases = ["channellist", "all channels"]
|
||||
key = "@channels"
|
||||
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
"Implement function"
|
||||
|
||||
caller = self.caller
|
||||
|
||||
string = "All channels (use comlist to see your subscriptions)\n"
|
||||
|
||||
string += "** Channel Perms Description\n"
|
||||
channels = Channel.objects.get_all_channels()
|
||||
|
||||
# all channels we have available to listen to
|
||||
channels = [chan for chan in Channel.objects.get_all_channels() if has_perm(caller, chan, 'can_listen')]
|
||||
if not channels:
|
||||
string += "(No channels) "
|
||||
for chan in channels:
|
||||
if has_perm(caller, chan, 'can_listen'):
|
||||
string += " %s%s %-15.14s%-22.15s%s\n" % \
|
||||
('-',
|
||||
'-',
|
||||
chan.key,
|
||||
chan.permissions,
|
||||
#chan.get_owner().get_name(show_dbref=False),
|
||||
chan.desc)
|
||||
string = string[:-1]
|
||||
#s += "** End of Channel List **"
|
||||
caller.msg("No channels available")
|
||||
return
|
||||
# all channel we are already subscribed to
|
||||
subs = [conn.channel for conn in ChannelConnection.objects.get_all_player_connections(caller.player)]
|
||||
|
||||
if self.cmdstring != "comlist":
|
||||
|
||||
string = "\nAll available channels:"
|
||||
cols = [[" "], ["Channel"], ["Aliases"], ["Perms"], ["Description"]]
|
||||
for chan in channels:
|
||||
if chan in subs:
|
||||
cols[0].append(">")
|
||||
else:
|
||||
cols[0].append(" ")
|
||||
cols[1].append(chan.key)
|
||||
cols[2].append(",".join(chan.aliases))
|
||||
cols[3].append(",".join(chan.permissions))
|
||||
cols[4].append(chan.desc)
|
||||
# put into table
|
||||
for ir, row in enumerate(utils.format_table(cols)):
|
||||
if ir == 0:
|
||||
string += "\n{w" + "".join(row) + "{n"
|
||||
else:
|
||||
string += "\n" + "".join(row)
|
||||
self.caller.msg(string)
|
||||
|
||||
string = "\nYour channel subscriptions:"
|
||||
if not subs:
|
||||
string += "(None)"
|
||||
else:
|
||||
nicks = [nick for nick in caller.nicks if nick.db_type == 'channel']
|
||||
print nicks
|
||||
cols = [["Channel"], ["Aliases"], ["Description"]]
|
||||
for chan in subs:
|
||||
cols[0].append(chan.key)
|
||||
cols[1].append(",".join([nick.db_nick for nick in nicks
|
||||
if nick.db_real.lower() == chan.key.lower()] + chan.aliases))
|
||||
cols[2].append(chan.desc)
|
||||
# put into table
|
||||
for ir, row in enumerate(utils.format_table(cols)):
|
||||
if ir == 0:
|
||||
string += "\n{w" + "".join(row) + "{n"
|
||||
else:
|
||||
string += "\n" + "".join(row)
|
||||
caller.msg(string)
|
||||
|
||||
class CmdCdestroy(MuxCommand):
|
||||
|
|
@ -349,11 +332,12 @@ class CmdCdestroy(MuxCommand):
|
|||
caller.msg("You are not allowed to do that.")
|
||||
return
|
||||
|
||||
message = "Channel %s is being destroyed. Make sure to change your aliases." % channel.key
|
||||
message = "%s is being destroyed. Make sure to change your aliases." % channel
|
||||
msgobj = create.create_message(caller, message, channel)
|
||||
channel.msg(msgobj)
|
||||
channel.delete()
|
||||
caller.msg("Channel %s was destroyed." % channel)
|
||||
CHANNELHANDLER.update()
|
||||
caller.msg("%s was destroyed." % channel)
|
||||
|
||||
|
||||
## def cmd_cset(self):
|
||||
|
|
@ -741,7 +725,7 @@ class CmdPage(MuxCommand):
|
|||
|
||||
if 'list' in self.switches:
|
||||
pages = pages_we_sent + pages_we_got
|
||||
pages.sort(lambda x,y: cmp(x.date_sent, y.date_sent))
|
||||
pages.sort(lambda x, y: cmp(x.date_sent, y.date_sent))
|
||||
|
||||
number = 10
|
||||
if self.args:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from src.permissions.models import PermissionGroup
|
|||
from src.permissions.permissions import has_perm, has_perm_string
|
||||
from src.objects.models import HANDLE_SEARCH_ERRORS
|
||||
from src.utils import utils
|
||||
from src.objects.models import Nick
|
||||
from src.commands.default.muxcommand import MuxCommand
|
||||
|
||||
class CmdHome(MuxCommand):
|
||||
|
|
@ -41,8 +42,9 @@ class CmdLook(MuxCommand):
|
|||
Usage:
|
||||
look
|
||||
look <obj>
|
||||
look *<player>
|
||||
|
||||
Observes your location or objects in your vicinity.
|
||||
Observes your location or objects in your vicinity.
|
||||
"""
|
||||
key = "look"
|
||||
aliases = ["l"]
|
||||
|
|
@ -56,7 +58,7 @@ class CmdLook(MuxCommand):
|
|||
|
||||
if args:
|
||||
# Use search to handle duplicate/nonexistant results.
|
||||
looking_at_obj = caller.search(args)
|
||||
looking_at_obj = caller.search(args, use_nicks=True)
|
||||
if not looking_at_obj:
|
||||
return
|
||||
else:
|
||||
|
|
@ -64,6 +66,9 @@ class CmdLook(MuxCommand):
|
|||
if not looking_at_obj:
|
||||
caller.msg("Location: None")
|
||||
return
|
||||
if not hasattr(looking_at_obj, 'return_appearance'):
|
||||
# this is likely due to us having a player instead
|
||||
looking_at_obj = looking_at_obj.character
|
||||
# get object's appearance
|
||||
caller.msg(looking_at_obj.return_appearance(caller))
|
||||
# the object's at_desc() method.
|
||||
|
|
@ -109,16 +114,18 @@ class CmdNick(MuxCommand):
|
|||
Define a personal alias/nick
|
||||
|
||||
Usage:
|
||||
alias[/switches] <alias> = [<string>]
|
||||
nick ''
|
||||
nick[/switches] <nickname> = [<string>]
|
||||
alias ''
|
||||
|
||||
Switches: obj - alias an object
|
||||
Switches:
|
||||
object - alias an object
|
||||
player - alias a player
|
||||
clearall - clear all your aliases
|
||||
list - show all defined aliases
|
||||
|
||||
If no switch is given, a command/channel alias is created, used
|
||||
to replace strings before sending the command.
|
||||
If no switch is given, a command alias is created, used
|
||||
to replace strings before sending the command. Give an empty
|
||||
right-hand side to clear the nick
|
||||
|
||||
Creates a personal nick for some in-game object or
|
||||
string. When you enter that string, it will be replaced
|
||||
|
|
@ -129,8 +136,8 @@ class CmdNick(MuxCommand):
|
|||
if you want to change the inherent aliases of an object,
|
||||
use the @alias command instead.
|
||||
"""
|
||||
key = "nickname"
|
||||
aliases = ["nick, @nick, alias"]
|
||||
key = "nick"
|
||||
aliases = ["nickname", "nicks", "@nick", "alias"]
|
||||
|
||||
def func(self):
|
||||
"Create the nickname"
|
||||
|
|
@ -138,55 +145,58 @@ class CmdNick(MuxCommand):
|
|||
caller = self.caller
|
||||
switches = self.switches
|
||||
|
||||
if 'list' in switches:
|
||||
string = "{wAliases:{n \n"
|
||||
string = string + "\n\r".join(["%s = %s" % (alias, replace)
|
||||
for alias, replace
|
||||
in caller.nicks.items()])
|
||||
nicks = Nick.objects.filter(db_obj=caller.dbobj).exclude(db_type="channel")
|
||||
if 'list' in switches or self.cmdstring == "nicks":
|
||||
string = "{wDefined Nicks:{n"
|
||||
cols = [["Type"],["Nickname"],["Translates-to"] ]
|
||||
for nick in nicks:
|
||||
cols[0].append(nick.db_type)
|
||||
cols[1].append(nick.db_nick)
|
||||
cols[2].append(nick.db_real)
|
||||
for ir, row in enumerate(utils.format_table(cols)):
|
||||
if ir == 0:
|
||||
string += "\n{w" + "".join(row) + "{n"
|
||||
else:
|
||||
string += "\n" + "".join(row)
|
||||
caller.msg(string)
|
||||
return
|
||||
if 'clearall' in switches:
|
||||
del caller.nicks
|
||||
nicks.delete()
|
||||
caller.msg("Cleared all aliases.")
|
||||
return
|
||||
if not self.args or not self.lhs:
|
||||
caller.msg("Usage: nick[/switches] nickname = [realname]")
|
||||
return
|
||||
nick = self.lhs
|
||||
real = self.rhs
|
||||
|
||||
if real == nick:
|
||||
caller.msg("No point in setting nick same as the string to replace...")
|
||||
return
|
||||
|
||||
if not self.args or not self.lhs:
|
||||
caller.msg("Usage: alias[/switches] string = [alias]")
|
||||
return
|
||||
|
||||
alias = self.lhs
|
||||
rstring = self.rhs
|
||||
err = None
|
||||
if rstring == alias:
|
||||
err = "No point in setting alias same as the string to replace..."
|
||||
caller.msg(err)
|
||||
return
|
||||
elif 'obj' in switches:
|
||||
# object alias, for adressing objects
|
||||
# (including user-controlled ones)
|
||||
err = caller.set_nick("_obj:%s" % alias, rstring)
|
||||
atype = "Object"
|
||||
elif 'player' in switches:
|
||||
# player alias, used for messaging
|
||||
err = caller.set_nick("_player:%s" % alias, rstring)
|
||||
atype = "Player "
|
||||
else:
|
||||
# a command/channel alias - these are replaced if
|
||||
# they begin a command string.
|
||||
caller.msg(rstring)
|
||||
caller.msg("going in: %s %s" % (alias, rstring))
|
||||
err = caller.set_nick(alias, rstring)
|
||||
atype = "Command/channel "
|
||||
if err:
|
||||
if rstring:
|
||||
err = "%salias %s changed from '%s' to '%s'." % (atype, alias, err, rstring)
|
||||
# check so we have a suitable nick type
|
||||
if not any(True for switch in switches if switch in ("object", "player", "inputline")):
|
||||
switches = ["inputline"]
|
||||
string = ""
|
||||
for switch in switches:
|
||||
oldnick = Nick.objects.filter(db_obj=caller.dbobj, db_nick__iexact=nick, db_type__iexact=switch)
|
||||
if not real:
|
||||
# removal of nick
|
||||
if oldnick:
|
||||
# clear the alias
|
||||
string += "\nNick '%s' (= '%s') was cleared." % (nick, oldnick[0].db_real)
|
||||
caller.nickhandler(nick, nick_type=switch, delete=True)
|
||||
else:
|
||||
string += "\nNo nick '%s' found, so it could not be removed." % nick
|
||||
else:
|
||||
err = "Cleared %salias '%s'(='%s')." % (atype, alias, err)
|
||||
else:
|
||||
err = "Set %salias '%s' = '%s'" % (atype, alias, rstring)
|
||||
caller.msg(err.capitalize())
|
||||
|
||||
|
||||
# creating new nick
|
||||
if oldnick:
|
||||
string += "\nNick %s changed from '%s' to '%s'." % (nick, oldnick[0].db_real, real)
|
||||
else:
|
||||
string += "\nNick set: '%s' = '%s'." % (nick, real)
|
||||
caller.nickhandler(nick, real, nick_type=switch)
|
||||
caller.msg(string)
|
||||
|
||||
class CmdInventory(MuxCommand):
|
||||
"""
|
||||
inventory
|
||||
|
|
@ -362,8 +372,8 @@ class CmdWho(MuxCommand):
|
|||
plr_pobject = session.get_character()
|
||||
if show_session_data:
|
||||
table[0].append(plr_pobject.name[:25])
|
||||
table[1].append(utils.time_format(delta_conn,0))
|
||||
table[2].append(utils.time_format(delta_cmd,1))
|
||||
table[1].append(utils.time_format(delta_conn, 0))
|
||||
table[2].append(utils.time_format(delta_cmd, 1))
|
||||
table[3].append(plr_pobject.location.id)
|
||||
table[4].append(session.cmd_total)
|
||||
table[5].append(session.address[0])
|
||||
|
|
|
|||
|
|
@ -54,10 +54,10 @@ class CmdReload(MuxCommand):
|
|||
if attempt < max_attempts-1:
|
||||
caller.msg(" Waiting for modules(s) to finish (%s) ..." % attempt)
|
||||
else:
|
||||
string = " ... The module(s) took too long to reload, "
|
||||
string = "{r ... The module(s) took too long to reload, "
|
||||
string += "\n so the remaining reloads where skipped."
|
||||
string += "\n Re-run @reload again when modules have fully "
|
||||
string += "\n re-initialized."
|
||||
string += "\n re-initialized.{n"
|
||||
caller.msg(string)
|
||||
|
||||
class CmdPy(MuxCommand):
|
||||
|
|
|
|||
|
|
@ -34,14 +34,15 @@ class ChannelCommand(command.Command):
|
|||
Usage:
|
||||
<channel name or alias> <message>
|
||||
|
||||
This is a channel. You can send to it by entering
|
||||
its name or alias, followed by the text you want to send.
|
||||
This is a channel. If you have subscribed to it, you can send to
|
||||
it by entering its name or alias, followed by the text you want to
|
||||
send.
|
||||
"""
|
||||
# this flag is what identifies this cmd as a channel cmd
|
||||
# and branches off to the system send-to-channel command
|
||||
# (which is customizable by admin)
|
||||
key = "general"
|
||||
help_category = "Channels"
|
||||
help_category = "Channel Names"
|
||||
permissions = "cmd:use_channels"
|
||||
is_channel = True
|
||||
obj = None
|
||||
|
|
@ -64,6 +65,7 @@ class ChannelCommand(command.Command):
|
|||
caller.msg("Say what?")
|
||||
return
|
||||
channel = Channel.objects.get_channel(channelkey)
|
||||
|
||||
if not channel:
|
||||
caller.msg("Channel '%s' not found." % channelkey)
|
||||
return
|
||||
|
|
@ -93,8 +95,8 @@ class ChannelHandler(object):
|
|||
|
||||
def __str__(self):
|
||||
return ", ".join(str(cmd) for cmd in self.cached_channel_cmds)
|
||||
|
||||
def reset(self):
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Reset the cache storage.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -232,13 +232,7 @@ class ChannelManager(models.Manager):
|
|||
from src.comms.channelhandler import CHANNELHANDLER
|
||||
CHANNELHANDLER.update()
|
||||
return None
|
||||
|
||||
def has_connection(self, player, channel):
|
||||
"Check so the player is really listening to this channel."
|
||||
ChannelConnection = ContentType.objects.get(app_label="comms",
|
||||
model="channelconnection").model_class()
|
||||
return ChannelConnection.objects.has_connection(player, channel)
|
||||
|
||||
|
||||
def get_all_connections(self, channel):
|
||||
"""
|
||||
Return the connections of all players listening
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ class Channel(SharedMemoryModel):
|
|||
Checks so this player is actually listening
|
||||
to this channel.
|
||||
"""
|
||||
return Channel.objects.has_connection(player, self)
|
||||
return ChannelConnection.objects.has_connection(player, self)
|
||||
|
||||
def msg(self, msgobj, from_obj=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class ExitHandler(object):
|
|||
"Setup cache storage"
|
||||
self.cached_exit_cmds = {}
|
||||
|
||||
def reset(self, exitcmd=None):
|
||||
def clear(self, exitcmd=None):
|
||||
"""
|
||||
Reset cache storage. If obj is given, only remove
|
||||
that object from cache.
|
||||
|
|
|
|||
|
|
@ -13,10 +13,7 @@ Attributes are separate objects that store values persistently onto
|
|||
the database object. Like everything else, they can be accessed
|
||||
transparently through the decorating TypeClass.
|
||||
"""
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
|
|
@ -74,6 +71,39 @@ class Alias(SharedMemoryModel):
|
|||
verbose_name = "Object alias"
|
||||
verbose_name_plural = "Object aliases"
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# Nick
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
class Nick(SharedMemoryModel):
|
||||
"""
|
||||
This model holds whichever alternate names this object
|
||||
has for OTHER objects, but also for arbitrary strings,
|
||||
channels, players etc. Setting a nick does not affect
|
||||
the nicknamed object at all (as opposed to Aliases above),
|
||||
and only this object will be able to refer to the nicknamed
|
||||
object by the given nick.
|
||||
|
||||
The default nick types used by Evennia are:
|
||||
inputline (default) - match against all input
|
||||
player - match against player searches
|
||||
obj - match against object searches
|
||||
channel - used to store own names for channels
|
||||
|
||||
"""
|
||||
db_nick = models.CharField(max_length=255, db_index=True) # the nick
|
||||
db_real = models.TextField() # the aliased string
|
||||
db_type = models.CharField(default="inputline", max_length=16, null=True, blank=True) # the type of nick
|
||||
db_obj = models.ForeignKey("ObjectDB")
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
verbose_name = "Nickname"
|
||||
verbose_name_plural = "Nicknames"
|
||||
unique_together = ("db_nick", "db_type", "db_obj")
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# ObjectDB
|
||||
|
|
@ -140,7 +170,7 @@ class ObjectDB(TypedObject):
|
|||
blank=True, null=True)
|
||||
# pickled dictionary storing the object's assigned nicknames
|
||||
# (use the 'nicks' property to access)
|
||||
db_nicks = models.TextField(null=True, blank=True)
|
||||
db_nicks = models.ForeignKey(Nick, blank=True, null=True, db_index=True)
|
||||
|
||||
# Database manager
|
||||
objects = ObjectManager()
|
||||
|
|
@ -157,7 +187,7 @@ class ObjectDB(TypedObject):
|
|||
#@property
|
||||
def aliases_get(self):
|
||||
"Getter. Allows for value = self.aliases"
|
||||
return [alias.db_key for alias in Alias.objects.filter(db_obj=self)]
|
||||
return list(Alias.objects.filter(db_obj=self))
|
||||
#@aliases.setter
|
||||
def aliases_set(self, aliases):
|
||||
"Setter. Allows for self.aliases = value"
|
||||
|
|
@ -277,30 +307,17 @@ class ObjectDB(TypedObject):
|
|||
# nicks property (wraps db_nicks)
|
||||
#@property
|
||||
def nicks_get(self):
|
||||
"""
|
||||
Getter. Allows for value = self.nicks.
|
||||
This unpickles the nick dictionary.
|
||||
"""
|
||||
if self.db_nicks:
|
||||
return pickle.loads(str(self.db_nicks))
|
||||
return {}
|
||||
#@nicks.setter
|
||||
def nicks_set(self, nick_dict):
|
||||
"""
|
||||
Setter. Allows for self.nicks = nick_dict.
|
||||
This re-pickles the nick dictionary.
|
||||
"""
|
||||
if type(nick_dict) == dict:
|
||||
# only allow storing dicts.
|
||||
self.db_nicks = pickle.dumps(nick_dict)
|
||||
self.save()
|
||||
#@nicks.deleter
|
||||
"Getter. Allows for value = self.aliases"
|
||||
return list(Nick.objects.filter(db_obj=self))
|
||||
#@nick.setter
|
||||
def nicks_set(self, nicks):
|
||||
"""Setter is disabled. Use the nickhandler instead."""
|
||||
logger.log_errmsg("Nicks (%s) cannot be set through obj.nicks. Use obj.nickhandler instead." % nicks)
|
||||
#@nick.deleter
|
||||
def nicks_del(self):
|
||||
"""
|
||||
Deleter. Allows for del self.nicks.
|
||||
Don't delete nicks, set to empty dict
|
||||
"""
|
||||
self.db_nicks = {}
|
||||
"Deleter. Allows for del self.aliases"
|
||||
for nick in Nick.objects.filter(db_obj=self):
|
||||
nick.delete()
|
||||
nicks = property(nicks_get, nicks_set, nicks_del)
|
||||
|
||||
|
||||
|
|
@ -361,66 +378,55 @@ class ObjectDB(TypedObject):
|
|||
return [exi for exi in self.contents
|
||||
if exi.has_attribute('_destination')]
|
||||
exits = property(exits_get)
|
||||
|
||||
#
|
||||
# Nicks - custom nicknames
|
||||
#
|
||||
#
|
||||
# nicks - the object can with this create
|
||||
# personalized aliases for in-game words. Essentially
|
||||
# anything can be re-mapped, it's up to the implementation
|
||||
# as to how often the nick is checked and converted
|
||||
# to its real counterpart before entering into the system.
|
||||
#
|
||||
# Some system defaults:
|
||||
# {"nick":"cmdname", # re-maps command names(also channels)
|
||||
# "_player:nick":"player_name", # re-maps player names
|
||||
# "_obj:nick":"realname"} # re-maps object names
|
||||
#
|
||||
# Example: a nick 'obj:red' mapped to the word "big red man" would
|
||||
# allow you to search for the big red man with just 'red' (note
|
||||
# that it's dumb substitution though; red will always translate
|
||||
# to big red man when searching, regardless of if there is such
|
||||
# a man or not. Such logics need to implemented for your particular
|
||||
# game).
|
||||
#
|
||||
|
||||
def set_nick(self, nick, realname=None):
|
||||
|
||||
def nickhandler(self, nick, realname=None, nick_type="inputline", startswith=False, delete=False):
|
||||
"""
|
||||
This is a central method for getting and setting nicks
|
||||
- mappings of nicks to strings, objects etc. This is the main
|
||||
access method, use it in preference over the 'nicks' property.
|
||||
|
||||
Map a nick to a realname. Be careful if mapping an
|
||||
existing realname into a nick - you could make that
|
||||
realname inaccessible until you deleted the alias.
|
||||
Don't set realname to delete a previously set nick.
|
||||
To delete - don't set realname.
|
||||
|
||||
returns a string with the old realname that this alias
|
||||
used to map (now overwritten), in case the
|
||||
nickname was already defined before.
|
||||
"""
|
||||
if not nick:
|
||||
return
|
||||
if not realname:
|
||||
nicks = self.nicks
|
||||
delnick = "Old alias not found!"
|
||||
if nick in nicks:
|
||||
# delete the nick
|
||||
delnick = nicks[nick]
|
||||
del nicks[nick]
|
||||
self.nicks = nicks
|
||||
return delnick
|
||||
nick = nick.strip()
|
||||
realname = realname.strip()
|
||||
if nick == realname:
|
||||
return
|
||||
# set the new alias
|
||||
retval = None
|
||||
nicks = self.nicks
|
||||
if nick in nicks:
|
||||
retval = nicks[nick]
|
||||
nicks[nick] = realname
|
||||
self.nicks = nicks
|
||||
return retval
|
||||
|
||||
nick_types can be defined freely depending on implementation.
|
||||
The default nick_types used in Evennia are:
|
||||
inputline (default) - match nick against all input
|
||||
player - match nick against player searches
|
||||
obj - match nick against object searches
|
||||
channel - match nick when checking for channel aliases
|
||||
|
||||
the delete keyword will delete the given nick.
|
||||
"""
|
||||
if not nick or not nick.strip():
|
||||
return
|
||||
nick = nick.strip()
|
||||
query = Nick.objects.filter(db_obj=self, db_nick__iexact=nick)
|
||||
if nick_type:
|
||||
query = query.filter(db_type__iexact=nick_type)
|
||||
if delete:
|
||||
# remove the found nick(s)
|
||||
query.delete()
|
||||
elif realname == None:
|
||||
# we want to get the real name for the nick. If none is
|
||||
# found, we return the nick again
|
||||
query = query.values_list("db_real", flat=True)
|
||||
if query:
|
||||
return query[0]
|
||||
else:
|
||||
return nick
|
||||
else:
|
||||
# we want to assign a new nick
|
||||
real = realname.strip()
|
||||
if query:
|
||||
old_nick = query[0]
|
||||
old_nick.db_real = real
|
||||
old_nick.save()
|
||||
else:
|
||||
new_nick = Nick(db_nick=nick, db_real=real, db_type=nick_type, db_obj=self)
|
||||
new_nick.save()
|
||||
|
||||
#
|
||||
# Main Search method
|
||||
#
|
||||
|
|
@ -460,20 +466,10 @@ class ObjectDB(TypedObject):
|
|||
if use_nicks:
|
||||
if ostring.startswith('*'):
|
||||
# player nick replace
|
||||
for nick, real in ((nick.lstrip('_player:').strip(), real)
|
||||
for nick, real in self.nicks.items()
|
||||
if nick.strip().startswith('_player:')):
|
||||
if ostring.lstrip('*').lower() == nick.lower():
|
||||
ostring = "*%s" % real
|
||||
break
|
||||
ostring = "*%s" % self.nickhandler(ostring.lstrip('*'), nick_type="player")
|
||||
else:
|
||||
# object nick replace
|
||||
for nick, real in ((nick.lstrip('_obj:').strip(), real)
|
||||
for nick, real in self.nicks.items()
|
||||
if nick.strip().startswith('_obj:')):
|
||||
if ostring.lower() == nick.lower():
|
||||
ostring = real
|
||||
break
|
||||
ostring = self.nickhandler(ostring, nick_type="object")
|
||||
|
||||
results = ObjectDB.objects.object_search(self, ostring,
|
||||
global_search=global_search,
|
||||
|
|
@ -512,11 +508,13 @@ class ObjectDB(TypedObject):
|
|||
lets its typeclass execute the command.
|
||||
raw_string - raw command input coming from the command line.
|
||||
"""
|
||||
# nick replacement
|
||||
for nick, real in self.nicks.items():
|
||||
if raw_string.startswith(nick):
|
||||
raw_string = raw_string.replace(nick, real, 1)
|
||||
break
|
||||
# nick replacement - we require full-word matching.
|
||||
raw_list = raw_string.split(None)
|
||||
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
|
||||
for nick in Nick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
|
||||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
cmdhandler.cmdhandler(self.typeclass(self), raw_string)
|
||||
|
||||
def msg(self, message, from_obj=None, data=None):
|
||||
|
|
@ -532,7 +530,7 @@ class ObjectDB(TypedObject):
|
|||
# we use a different __getattribute__ to avoid recursive loops.
|
||||
|
||||
if object.__getattribute__(self, 'player'):
|
||||
object.__getattribute__(self, 'player').msg(message, data)
|
||||
object.__getattribute__(self, 'player').msg(message, from_obj, data)
|
||||
|
||||
def emit_to(self, message, from_obj=None, data=None):
|
||||
"Deprecated. Alias for msg"
|
||||
|
|
|
|||
|
|
@ -374,5 +374,5 @@ class Exit(Object):
|
|||
out of sync with the cache. You should do this also if
|
||||
overloading this function in a child class.
|
||||
"""
|
||||
EXITHANDLER.reset(self.dbobj)
|
||||
EXITHANDLER.clear(self.dbobj)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ if os.name == 'nt':
|
|||
from twisted.application import internet, service
|
||||
from twisted.internet import protocol, reactor, defer
|
||||
from twisted.web import server, static
|
||||
from twisted.python import threadpool
|
||||
from django.db import connection
|
||||
from django.conf import settings
|
||||
from src.utils import reloads
|
||||
|
|
@ -203,7 +202,8 @@ if WEBSERVER_ENABLED:
|
|||
|
||||
# a django-compatible webserver.
|
||||
|
||||
from src.server.webserver import DjangoWebRoot, WSGIWebServer#DjangoWebRoot
|
||||
from twisted.python import threadpool
|
||||
from src.server.webserver import DjangoWebRoot, WSGIWebServer
|
||||
|
||||
# start a thread pool and define the root url (/) as a wsgi resource
|
||||
# recognized by Django
|
||||
|
|
@ -221,7 +221,6 @@ if WEBSERVER_ENABLED:
|
|||
for port in WEBSERVER_PORTS:
|
||||
# create the webserver
|
||||
webserver = WSGIWebServer(threads, port, web_site)
|
||||
#webserver = internet.TCPServer(port, web_site)
|
||||
#webserver = internet.SSLServer(port, web_site)
|
||||
webserver.setName('EvenniaWebServer%s' % port)
|
||||
EVENNIA.services.addService(webserver)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ Web client server resource.
|
|||
The Evennia web client consists of two components running
|
||||
on twisted and django. They are both a part of the Evennia
|
||||
website url tree (so the testing website might be located
|
||||
on http://localhost:8020/, whereas the webclient can be
|
||||
found on http://localhost:8020/webclient.)
|
||||
on http://localhost:8000/, whereas the webclient can be
|
||||
found on http://localhost:8000/webclient.)
|
||||
|
||||
/webclient - this url is handled through django's template
|
||||
system and serves the html page for the client
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ class DjangoWebRoot(resource.Resource):
|
|||
path0 = request.prepath.pop(0)
|
||||
request.postpath.insert(0, path0)
|
||||
return self.wsgi_resource
|
||||
#
|
||||
# Threaded Webserver
|
||||
#
|
||||
|
||||
class WSGIWebServer(internet.TCPServer):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ CHANNEL_PUBLIC = ("Public", 'ooc', 'Public discussion',
|
|||
CHANNEL_MUDINFO = ("MUDinfo", '', 'Informative messages',
|
||||
'''chan_admin:has_id(1),
|
||||
chan_listen:Immortals,
|
||||
chan_send:Immportals''')
|
||||
chan_send:Immortals''')
|
||||
# Channel showing when new people connecting
|
||||
CHANNEL_CONNECTINFO = ("MUDconnections", ('connections, mud_conns'),
|
||||
'Connection log',
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ def create_message(senderobj, message, channels=None,
|
|||
new_message.save()
|
||||
return new_message
|
||||
|
||||
def create_channel(key, aliases=None, description=None,
|
||||
def create_channel(key, aliases=None, desc=None,
|
||||
permissions=None, keep_log=True):
|
||||
"""
|
||||
Create A communication Channel. A Channel serves as a central
|
||||
|
|
@ -356,7 +356,7 @@ def create_channel(key, aliases=None, description=None,
|
|||
if not is_iter(aliases):
|
||||
aliases = [aliases]
|
||||
new_channel.aliases = ",".join([str(alias) for alias in aliases])
|
||||
new_channel.description = description
|
||||
new_channel.desc = desc
|
||||
new_channel.keep_log = keep_log
|
||||
except IntegrityError:
|
||||
string = "Could not add channel: key '%s' already exists." % key
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ def reload_modules():
|
|||
|
||||
# clean out cache dictionary of typeclasses, exits and channe
|
||||
typeclassmodels.reset()
|
||||
exithandler.EXITHANDLER.reset()
|
||||
channelhandler.CHANNELHANDLER.reset()
|
||||
exithandler.EXITHANDLER.clear()
|
||||
channelhandler.CHANNELHANDLER.update()
|
||||
|
||||
def reload_scripts(scripts=None, obj=None, key=None,
|
||||
dbref=None, init_mode=False):
|
||||
|
|
@ -129,14 +129,17 @@ def cemit_info(message):
|
|||
Sends the info to a pre-set channel. This channel is
|
||||
set by CHANNEL_MUDINFO in settings.
|
||||
"""
|
||||
|
||||
logger.log_infomsg(message)
|
||||
try:
|
||||
infochan = settings.CHANNEL_MUDINFO
|
||||
infochan = Channel.objects.get_channel(infochan[0])
|
||||
except Exception:
|
||||
return
|
||||
pass
|
||||
if infochan:
|
||||
cname = infochan.key
|
||||
cmessage = "\n".join(["[%s]: %s" % (cname, line) for line in message.split('\n')])
|
||||
infochan.msg(cmessage)
|
||||
|
||||
else:
|
||||
cmessage = "\n".join(["[NO MUDINFO CHANNEL]: %s" % line for line in message.split('\n')])
|
||||
logger.log_infomsg(cmessage)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue