mirror of
https://github.com/evennia/evennia.git
synced 2026-03-29 03:57:17 +02:00
Move alias/connect setup to channel class rather than cmd
This commit is contained in:
parent
8e19017dc3
commit
51bef9bf97
8 changed files with 224 additions and 84 deletions
|
|
@ -315,6 +315,12 @@ gets its data from. A channel's log will rotate when it grows too big, which
|
|||
thus also automatically limits the max amount of history a user can view with
|
||||
`/history`.
|
||||
|
||||
The log file name is set on the channel class as the `log_file` property. This
|
||||
is a string that takes the formatting token `{channelname}` to be replaced with
|
||||
the (lower-case) name of the channel. By default the log is written to in the
|
||||
channel's `at_post_channel_msg` method.
|
||||
|
||||
|
||||
### Properties on Channels
|
||||
|
||||
Channels have all the standard properties of a Typeclassed entity (`key`,
|
||||
|
|
@ -323,16 +329,24 @@ see the [Channel api docs](api:evennia.comms.comms.DefaultChannel) for details.
|
|||
|
||||
- `send_to_online_only` - this class boolean defaults to `True` and is a
|
||||
sensible optimization since people offline people will not see the message anyway.
|
||||
- `log_to_file` - this is a string that determines the name of the channel log file. Default
|
||||
is `"channel_{channel_key}.log"`. You should usually not change this.
|
||||
- `log_file` - this is a string that determines the name of the channel log file. Default
|
||||
is `"channel_{channelname}.log"`. The log file will appear in `settings.LOG_DIR` (usually
|
||||
`mygame/server/logs/`). You should usually not change this.
|
||||
- `channel_prefix_string` - this property is a string to easily change how
|
||||
the channel is prefixed. It takes the `channel_key` format key. Default is `"[{channel_key}] "`
|
||||
the channel is prefixed. It takes the `channelname` format key. Default is `"[{channelname}] "`
|
||||
and produces output like `[public] ...``.
|
||||
- `subscriptions` - this is the [SubscriptionHandler](`api:evennia.comms.comms.SubscriptionHandler`), which
|
||||
has methods `has`, `add`, `remove`, `all`, `clear` and also `online` (to get
|
||||
only actually online channel-members).
|
||||
- `wholist`, `mutelist`, `banlist` are properties that return a list of subscribers,
|
||||
as well as who are currently muted or banned.
|
||||
- `channel_msg_nick_pattern` - this is a regex pattern for performing the in-place nick
|
||||
replacement (detect that `channelalias <msg` means that you want to send a message to a channel).
|
||||
This pattern accepts an `{alias}` formatting marker. Don't mess with this unless you really
|
||||
want to change how channels work.
|
||||
- `channel_msg_nick_replacement` - this is a string on the [nick replacement
|
||||
- form](Nicks). It accepts the `{channelname}` formatting tag. This is strongly tied to the
|
||||
`channel` command and is by default `channel {channelname} = $1`.
|
||||
|
||||
Notable `Channel` hooks:
|
||||
|
||||
|
|
@ -347,12 +361,19 @@ Notable `Channel` hooks:
|
|||
also just remove that call.
|
||||
- every channel message. By default it just returns `channel_prefix_string`.
|
||||
- `has_connection(subscriber)` - shortcut to check if an entity subscribes to
|
||||
this channel
|
||||
this channel.
|
||||
- `mute/unmute(subscriber)` - this mutes the channel for this user.
|
||||
- `ban/unban(subscriber)` - adds/remove user from banlist.
|
||||
- `connect/disconnect(subscriber)` - adds/removes a subscriber.
|
||||
- `add_user_channel_alias(user, alias, **kwargs)` - sets up a user-nick for this channel. This is
|
||||
what maps e.g. `alias <msg>` to `channel channelname = <msg>`.
|
||||
- `remove_user_channel_alias(user, alias, **kwargs)` - remove an alias. Note that this is
|
||||
a class-method that will happily remove found channel-aliases from the user linked to _any_
|
||||
channel, not only from the channel the method is called on.
|
||||
- `pre_join_channel(subscriber)` - if this returns `False`, connection will be refused.
|
||||
- `post_join_channel(subscriber)` - unused by default.
|
||||
- `post_join_channel(subscriber)` - by default this sets up a users's channel-nicks/aliases.
|
||||
- `pre_leave_channel(subscriber)` - if this returns `False`, the user is not allowed to leave.
|
||||
- `post_leave_channel(subscriber)` - unused by default.
|
||||
- `post_leave_channel(subscriber)` - this will clean up any channel aliases/nicks of the user.
|
||||
- `delete` the standard typeclass-delete mechanism will also automatically un-subscribe all
|
||||
subscribers (and thus wipe all their aliases).
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from evennia.comms.models import Msg
|
|||
from evennia.accounts.models import AccountDB
|
||||
from evennia.accounts import bots
|
||||
from evennia.locks.lockhandler import LockException
|
||||
from evennia.comms.comms import DefaultChannel
|
||||
from evennia.utils import create, logger, utils
|
||||
from evennia.utils.logger import tail_log_file
|
||||
from evennia.utils.utils import class_from_module
|
||||
|
|
@ -229,17 +230,6 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
# disable this in child command classes if wanting on-character channels
|
||||
account_caller = True
|
||||
|
||||
# note - changing this will invalidate existing aliases in db
|
||||
# channel_msg_nick_alias = r"{alias}\s*?(?P<arg1>.+?){{0,1}}"
|
||||
channel_msg_nick_alias = r"{alias}\s*?|{alias}\s+?(?P<arg1>.+?)"
|
||||
channel_msg_nick_replacement = "channel {channelname} = $1"
|
||||
|
||||
# to make it easier to override help functionality, we add the ability to
|
||||
# tweak access to different sub-functionality. Note that the system will
|
||||
# still check control lock etc even if you can use this functionality.
|
||||
# changing these does not change access to this command itself (that's the
|
||||
# locks property)
|
||||
|
||||
def search_channel(self, channelname, exact=False, handle_errors=True):
|
||||
"""
|
||||
Helper function for searching for a single channel with some error
|
||||
|
|
@ -323,9 +313,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
caller = self.caller
|
||||
|
||||
log_file = channel.attributes.get(
|
||||
"log_file", default=channel.log_to_file.format(channel_key=channel.key))
|
||||
log_file = channel.get_log_filename()
|
||||
|
||||
def send_msg(lines):
|
||||
return self.msg(
|
||||
|
|
@ -351,11 +339,9 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
if channel.has_connection(caller):
|
||||
return False, f"Already listening to channel {channel.key}."
|
||||
result = channel.connect(caller)
|
||||
|
||||
key_and_aliases = [channel.key.lower()] + [alias.lower() for alias in channel.aliases.all()]
|
||||
for key_or_alias in key_and_aliases:
|
||||
self.add_alias(channel, key_or_alias)
|
||||
# this sets up aliases in post_join_channel by default
|
||||
result = channel.connect(caller)
|
||||
|
||||
return result, "" if result else f"Were not allowed to subscribe to channel {channel.key}"
|
||||
|
||||
|
|
@ -377,14 +363,10 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
if not channel.has_connection(caller):
|
||||
return False, f"Not listening to channel {channel.key}."
|
||||
# clear aliases
|
||||
for key_or_alias in self.get_channel_aliases(channel):
|
||||
self.remove_alias(key_or_alias, **kwargs)
|
||||
# remove the channel-name alias too
|
||||
msg_alias = self.channel_msg_nick_alias.format(alias=channel.key.lower())
|
||||
caller.nicks.remove(msg_alias, category="inputline", **kwargs)
|
||||
|
||||
# this will also clean aliases
|
||||
result = channel.disconnect(caller)
|
||||
|
||||
return result, "" if result else f"Could not unsubscribe from channel {channel.key}"
|
||||
|
||||
def add_alias(self, channel, alias, **kwargs):
|
||||
|
|
@ -401,7 +383,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
we need to be able to reference this channel easily. The other
|
||||
is a templated nick to easily be able to send messages to the
|
||||
channel without needing to give the full `channel` command. The
|
||||
structure of this nick is given by `self.channel_msg_nick_alias`
|
||||
structure of this nick is given by `self.channel_msg_pattern`
|
||||
and `self.channel_msg_nick_replacement`. By default it maps
|
||||
`alias <msg> -> channel <channelname> = <msg>`, so that you can
|
||||
for example just write `pub Hello` to send a message.
|
||||
|
|
@ -410,16 +392,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
for sending to channel using the main channel command.
|
||||
|
||||
"""
|
||||
chan_key = channel.key.lower()
|
||||
# the message-pattern allows us to type the channel on its own without
|
||||
# needing to use the `channel` command explicitly.
|
||||
msg_pattern = self.channel_msg_nick_alias.format(alias=alias)
|
||||
msg_replacement = self.channel_msg_nick_replacement.format(channelname=chan_key)
|
||||
|
||||
if chan_key != alias:
|
||||
self.caller.nicks.add(alias, chan_key, category="channel", **kwargs)
|
||||
self.caller.nicks.add(msg_pattern, msg_replacement, category="inputline",
|
||||
pattern_is_regex=True, **kwargs)
|
||||
channel.add_user_channel_alias(self.caller, alias, **kwargs)
|
||||
|
||||
def remove_alias(self, alias, **kwargs):
|
||||
"""
|
||||
|
|
@ -440,13 +413,9 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
nick used for easily sending messages to the channel.
|
||||
|
||||
"""
|
||||
caller = self.caller
|
||||
if caller.nicks.get(alias, category="channel", **kwargs):
|
||||
caller.nicks.remove(alias, category="chan nel", **kwargs)
|
||||
msg_alias = self.channel_msg_nick_alias.format(alias=alias)
|
||||
caller.nicks.remove(msg_alias, category="inputline", **kwargs)
|
||||
if self.caller.nicks.has(alias, category="channel", **kwargs):
|
||||
DefaultChannel.remove_user_channel_alias(self.caller, alias)
|
||||
return True, ""
|
||||
|
||||
return False, "No such alias was defined."
|
||||
|
||||
def get_channel_aliases(self, channel):
|
||||
|
|
@ -462,7 +431,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
chan_key = channel.key.lower()
|
||||
nicktuples = self.caller.nicks.get(category="channel", return_tuple=True)
|
||||
nicktuples = self.caller.nicks.get(category="channel", return_tuple=True, return_list=True)
|
||||
if nicktuples:
|
||||
return [tup[2] for tup in nicktuples if tup[3].lower() == chan_key]
|
||||
return []
|
||||
|
|
@ -915,6 +884,8 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
# first 'channel name' is in fact 'channelname text'
|
||||
no_rhs_channel_name = self.args.split(" ", 1)[0]
|
||||
possible_lhs_message = self.args[len(no_rhs_channel_name):]
|
||||
if possible_lhs_message.strip() == '=':
|
||||
possible_lhs_message = ""
|
||||
channel_names.append(no_rhs_channel_name)
|
||||
|
||||
|
||||
|
|
@ -952,13 +923,10 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
subscribed, available = self.list_channels()
|
||||
if channel in subscribed:
|
||||
table = self.display_subbed_channels([channel])
|
||||
inputname = self.raw_cmdname
|
||||
if inputname.lower() != channel.key.lower():
|
||||
header = f"Channel |w{inputname}|n (alias for {channel.key} channel)"
|
||||
else:
|
||||
header = f"Channel |w{channel.key}|n"
|
||||
self.msg(f"{header}\n(use |w{inputname} <msg>|n to chat and "
|
||||
f"the 'channel' command to customize)\n{table}")
|
||||
header = f"Channel |w{channel.key}|n"
|
||||
self.msg(f"{header}\n(use |w{channel.key} <msg>|n (or a channel-alias) "
|
||||
f"to chat and the 'channel' command "
|
||||
f"to customize)\n{table}")
|
||||
elif channel in available:
|
||||
table = self.display_all_channels([], [channel])
|
||||
self.msg(
|
||||
|
|
@ -1055,7 +1023,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
ask_yes_no(
|
||||
caller,
|
||||
prompt=f"Are you sure you want to delete channel '{channel.key}' "
|
||||
"(make sure name is correct!)? This will disconnect and "
|
||||
"(make sure name is correct!)?\nThis will disconnect and "
|
||||
"remove all users' aliases. {options}?",
|
||||
yes_action=_perform_delete,
|
||||
no_action="Aborted.",
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
Class-level variables:
|
||||
- `send_to_online_only` (bool, default True) - if set, will only try to
|
||||
send to subscribers that are actually active. This is a useful optimization.
|
||||
- `log_to_file` (str, default `"channel_{channel_key}.log"`). This is the
|
||||
log file to which the channel history will be saved. The `{channel_key}` tag
|
||||
- `log_file` (str, default `"channel_{channelname}.log"`). This is the
|
||||
log file to which the channel history will be saved. The `{channelname}` tag
|
||||
will be replaced by the key of the Channel. If an Attribute 'log_file'
|
||||
is set, this will be used instead. If this is None and no Attribute is found,
|
||||
no history will be saved.
|
||||
- `channel_prefix_string` (str, default `"[{channel_key} ]"`) - this is used
|
||||
- `channel_prefix_string` (str, default `"[{channelname} ]"`) - this is used
|
||||
as a simple template to get the channel prefix with `.channel_prefix()`.
|
||||
|
||||
"""
|
||||
|
|
@ -40,10 +40,15 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
send_to_online_only = True
|
||||
# store log in log file. `channel_key tag will be replace with key of channel.
|
||||
# Will use log_file Attribute first, if given
|
||||
log_to_file = "channel_{channel_key}.log"
|
||||
log_file = "channel_{channelname}.log"
|
||||
# which prefix to use when showing were a message is coming from. Set to
|
||||
# None to disable and set this later.
|
||||
channel_prefix_string = "[{channel_key}] "
|
||||
channel_prefix_string = "[{channelname}] "
|
||||
|
||||
# default nick-alias replacements (default using the 'channel' command)
|
||||
channel_msg_nick_pattern = r"{alias}\s*?|{alias}\s+?(?P<arg1>.+?)"
|
||||
channel_msg_nick_replacement = "channel {channelname} = $1"
|
||||
|
||||
|
||||
def at_first_save(self):
|
||||
"""
|
||||
|
|
@ -54,7 +59,6 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
"""
|
||||
self.basetype_setup()
|
||||
self.at_channel_creation()
|
||||
self.attributes.add("log_file", "channel_%s.log" % self.key)
|
||||
if hasattr(self, "_createdict"):
|
||||
# this is only set if the channel was created
|
||||
# with the utils.create.create_channel function.
|
||||
|
|
@ -78,6 +82,10 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
def basetype_setup(self):
|
||||
self.locks.add("send:all();listen:all();control:perm(Admin)")
|
||||
|
||||
# make sure we don't have access to a same-named old channel's history.
|
||||
log_file = self.get_log_filename()
|
||||
logger.rotate_log_file(log_file, num_lines_to_append=0)
|
||||
|
||||
def at_channel_creation(self):
|
||||
"""
|
||||
Called once, when the channel is first created.
|
||||
|
|
@ -87,6 +95,33 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
|
||||
# helper methods, for easy overloading
|
||||
|
||||
_log_file = None
|
||||
|
||||
def get_log_filename(self):
|
||||
"""
|
||||
File name to use for channel log.
|
||||
|
||||
Returns:
|
||||
str: The filename to use (this is always assumed to be inside
|
||||
settings.LOG_DIR)
|
||||
|
||||
"""
|
||||
if not self._log_file:
|
||||
self._log_file = self.attributes.get(
|
||||
"log_file", self.log_file.format(channelname=self.key.lower()))
|
||||
return self._log_file
|
||||
|
||||
def set_log_filename(self, filename):
|
||||
"""
|
||||
Set a custom log filename.
|
||||
|
||||
Args:
|
||||
filename (str): The filename to set. This is a path starting from
|
||||
inside the settings.LOG_DIR location.
|
||||
|
||||
"""
|
||||
self.attributes.add("log_file", filename)
|
||||
|
||||
def has_connection(self, subscriber):
|
||||
"""
|
||||
Checks so this account is actually listening
|
||||
|
|
@ -368,6 +403,8 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
"""
|
||||
self.attributes.clear()
|
||||
self.aliases.clear()
|
||||
for subscriber in self.subscriptions.all():
|
||||
self.disconnect(subscriber)
|
||||
super().delete()
|
||||
|
||||
def channel_prefix(self):
|
||||
|
|
@ -378,7 +415,73 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
str: The channel prefix.
|
||||
|
||||
"""
|
||||
return self.channel_prefix_string.format(channel_key=self.key)
|
||||
return self.channel_prefix_string.format(channelname=self.key)
|
||||
|
||||
def add_user_channel_alias(self, user, alias, **kwargs):
|
||||
"""
|
||||
Add a personal user-alias for this channel to a given subscriber.
|
||||
|
||||
Args:
|
||||
user (Object or Account): The one to alias this channel.
|
||||
alias (str): The desired alias.
|
||||
|
||||
Note:
|
||||
This is tightly coupled to the default `channel` command. If you
|
||||
change that, you need to change this as well.
|
||||
|
||||
We add two nicks - one is a plain `alias -> channel.key` that
|
||||
users need to be able to reference this channel easily. The other
|
||||
is a templated nick to easily be able to send messages to the
|
||||
channel without needing to give the full `channel` command. The
|
||||
structure of this nick is given by `self.channel_msg_nick_pattern`
|
||||
and `self.channel_msg_nick_replacement`. By default it maps
|
||||
`alias <msg> -> channel <channelname> = <msg>`, so that you can
|
||||
for example just write `pub Hello` to send a message.
|
||||
|
||||
The alias created is `alias $1 -> channel channel = $1`, to allow
|
||||
for sending to channel using the main channel command.
|
||||
|
||||
"""
|
||||
chan_key = self.key.lower()
|
||||
|
||||
# the message-pattern allows us to type the channel on its own without
|
||||
# needing to use the `channel` command explicitly.
|
||||
msg_nick_pattern = self.channel_msg_nick_pattern.format(alias=alias)
|
||||
msg_nick_replacement = self.channel_msg_nick_replacement.format(channelname=chan_key)
|
||||
user.nicks.add(msg_nick_pattern, msg_nick_replacement, category="inputline",
|
||||
pattern_is_regex=True, **kwargs)
|
||||
|
||||
if chan_key != alias:
|
||||
# this allows for using the alias for general channel lookups
|
||||
user.nicks.add(alias, chan_key, category="channel", **kwargs)
|
||||
|
||||
@classmethod
|
||||
def remove_user_channel_alias(cls, user, alias, **kwargs):
|
||||
"""
|
||||
Remove a personal channel alias from a user.
|
||||
|
||||
Args:
|
||||
user (Object or Account): The user to remove an alias from.
|
||||
alias (str): The alias to remove.
|
||||
**kwargs: Unused by default. Can be used to pass extra variables
|
||||
into a custom implementation.
|
||||
|
||||
Notes:
|
||||
The channel-alias actually consists of two aliases - one
|
||||
channel-based one for searching channels with the alias and one
|
||||
inputline one for doing the 'channelalias msg' - call.
|
||||
|
||||
This is a classmethod because it doesn't actually operate on the
|
||||
channel instance.
|
||||
|
||||
It sits on the channel because the nick structure for this is
|
||||
pretty complex and needs to be located in a central place (rather
|
||||
on, say, the channel command).
|
||||
|
||||
"""
|
||||
user.nicks.remove(alias, category="channel", **kwargs)
|
||||
msg_nick_pattern = cls.channel_msg_nick_pattern.format(alias=alias)
|
||||
user.nicks.remove(msg_nick_pattern, category="inputline", **kwargs)
|
||||
|
||||
def at_pre_msg(self, message, **kwargs):
|
||||
"""
|
||||
|
|
@ -472,9 +575,7 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
|
||||
"""
|
||||
# save channel history to log file
|
||||
default_log_file = (self.log_to_file.format(channel_key=self.key)
|
||||
if self.log_to_file else None)
|
||||
log_file = self.attributes.get("log_file", default=default_log_file)
|
||||
log_file = self.get_log_filename()
|
||||
if log_file:
|
||||
senders = ",".join(sender.key for sender in kwargs.get("senders", []))
|
||||
senders = f"{senders}: " if senders else ""
|
||||
|
|
@ -506,8 +607,13 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
**kwargs (dict): Arbitrary, optional arguments for users
|
||||
overriding the call (unused by default).
|
||||
|
||||
Notes:
|
||||
By default this adds the needed channel nicks to the joiner.
|
||||
|
||||
"""
|
||||
pass
|
||||
key_and_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()]
|
||||
for key_or_alias in key_and_aliases:
|
||||
self.add_user_channel_alias(joiner, key_or_alias, **kwargs)
|
||||
|
||||
def pre_leave_channel(self, leaver, **kwargs):
|
||||
"""
|
||||
|
|
@ -535,7 +641,12 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
overriding the call (unused by default).
|
||||
|
||||
"""
|
||||
pass
|
||||
chan_key = self.key.lower()
|
||||
key_or_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()]
|
||||
nicktuples = leaver.nicks.get(category="channel", return_tuple=True, return_list=True)
|
||||
key_or_aliases += [tup[2] for tup in nicktuples if tup[3].lower() == chan_key]
|
||||
for key_or_alias in key_or_aliases:
|
||||
self.remove_user_channel_alias(leaver, key_or_alias, **kwargs)
|
||||
|
||||
def at_init(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ class CraftingRecipeBase:
|
|||
are optional but will be passed into all of the following hooks.
|
||||
2. `.pre_craft(**kwargs)` - this normally validates inputs and stores them in
|
||||
`.validated_inputs.`. Raises `CraftingValidationError` otherwise.
|
||||
4. `.craft(**kwargs)` - should return the crafted item(s) or the empty list. Any
|
||||
4. `.do_craft(**kwargs)` - should return the crafted item(s) or the empty list. Any
|
||||
crafting errors should be immediately reported to user.
|
||||
5. `.post_craft(crafted_result, **kwargs)`- always called, even if `pre_craft`
|
||||
raised a `CraftingError` or `CraftingValidationError`.
|
||||
|
|
@ -252,7 +252,7 @@ class CraftingRecipeBase:
|
|||
else:
|
||||
raise CraftingValidationError
|
||||
|
||||
def craft(self, **kwargs):
|
||||
def do_craft(self, **kwargs):
|
||||
"""
|
||||
Hook to override.
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ class CraftingRecipeBase:
|
|||
method is to delete the inputs.
|
||||
|
||||
Args:
|
||||
crafting_result (any): The outcome of crafting, as returned by `craft()`.
|
||||
crafting_result (any): The outcome of crafting, as returned by `do_craft`.
|
||||
**kwargs: Any extra flags passed at initialization.
|
||||
|
||||
Returns:
|
||||
|
|
@ -324,7 +324,7 @@ class CraftingRecipeBase:
|
|||
if raise_exception:
|
||||
raise
|
||||
else:
|
||||
craft_result = self.craft(**craft_kwargs)
|
||||
craft_result = self.do_craft(**craft_kwargs)
|
||||
finally:
|
||||
craft_result = self.post_craft(craft_result, **craft_kwargs)
|
||||
except (CraftingError, CraftingValidationError):
|
||||
|
|
@ -455,7 +455,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
|||
3. `.pre_craft(**kwargs)` should handle validation of inputs. Results should
|
||||
be stored in `validated_consumables/tools` respectively. Raises `CraftingValidationError`
|
||||
otherwise.
|
||||
4. `.craft(**kwargs)` will not be called if validation failed. Should return
|
||||
4. `.do_craft(**kwargs)` will not be called if validation failed. Should return
|
||||
a list of the things crafted.
|
||||
5. `.post_craft(crafting_result, **kwargs)` is always called, also if validation
|
||||
failed (`crafting_result` will then be falsy). It does any cleanup. By default
|
||||
|
|
@ -819,7 +819,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
|||
self.validated_tools = tools
|
||||
self.validated_consumables = consumables
|
||||
|
||||
def craft(self, **kwargs):
|
||||
def do_craft(self, **kwargs):
|
||||
"""
|
||||
Hook to override. This will not be called if validation in `pre_craft`
|
||||
fails.
|
||||
|
|
@ -847,7 +847,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
|||
this method is to delete the inputs.
|
||||
|
||||
Args:
|
||||
craft_result (list): The crafted result, provided by `self.craft()`.
|
||||
craft_result (list): The crafted result, provided by `self.do_craft`.
|
||||
**kwargs (any): Passed from `self.craft`.
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class _SwordSmithingBaseRecipe(CraftingRecipe):
|
|||
"You work and work but you are not happy with the result. You need to start over."
|
||||
)
|
||||
|
||||
def do_craft(self, **kwargs):
|
||||
def craft(self, **kwargs):
|
||||
"""
|
||||
Making a sword blade takes skill. Here we emulate this by introducing a
|
||||
random chance of failure (in a real game this could be a skill check
|
||||
|
|
@ -126,7 +126,7 @@ class _SwordSmithingBaseRecipe(CraftingRecipe):
|
|||
if random.random() < 0.8:
|
||||
# 80% chance of success. This will spawn the sword and show
|
||||
# success-message.
|
||||
return super().do_craft(**kwargs)
|
||||
return super().craft(**kwargs)
|
||||
else:
|
||||
# fail and show failed message
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class TestCraftingRecipeBase(TestCase):
|
|||
"""Test craft hook, the main access method."""
|
||||
|
||||
expected_result = _TestMaterial("test_result")
|
||||
self.recipe.craft = mock.MagicMock(return_value=expected_result)
|
||||
self.recipe.do_craft = mock.MagicMock(return_value=expected_result)
|
||||
|
||||
self.assertTrue(self.recipe.allow_craft)
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ class TestCraftingRecipeBase(TestCase):
|
|||
|
||||
# check result
|
||||
self.assertEqual(result, expected_result)
|
||||
self.recipe.craft.assert_called_with(kw1=1, kw2=2)
|
||||
self.recipe.do_craft.assert_called_with(kw1=1, kw2=2)
|
||||
|
||||
# since allow_reuse is False, this usage should now be turned off
|
||||
self.assertFalse(self.recipe.allow_craft)
|
||||
|
|
@ -110,7 +110,7 @@ class TestCraftingRecipeBase(TestCase):
|
|||
def test_craft_hook__fail(self):
|
||||
"""Test failing the call"""
|
||||
|
||||
self.recipe.craft = mock.MagicMock(return_value=None)
|
||||
self.recipe.do_craft = mock.MagicMock(return_value=None)
|
||||
|
||||
# trigger exception
|
||||
with self.assertRaises(crafting.CraftingError):
|
||||
|
|
@ -213,7 +213,7 @@ class TestCraftingRecipe(TestCase):
|
|||
self.assertIsNotNone(self.tool1.pk)
|
||||
self.assertIsNotNone(self.tool2.pk)
|
||||
|
||||
def test_seed__succcess(self):
|
||||
def test_seed__success(self):
|
||||
"""Test seed helper classmethod"""
|
||||
|
||||
# needed for other dbs to pass seed
|
||||
|
|
|
|||
|
|
@ -995,7 +995,8 @@ class AttributeHandler:
|
|||
looked-after Attribute.
|
||||
default_access (bool, optional): If no `attrread` lock is set on
|
||||
object, this determines if the lock should then be passed or not.
|
||||
return_list (bool, optional):
|
||||
return_list (bool, optional): Always return a list, also if there is only
|
||||
one or zero matches found.
|
||||
|
||||
Returns:
|
||||
result (any or list): One or more matches for keys and/or
|
||||
|
|
|
|||
|
|
@ -357,12 +357,14 @@ class EvenniaLogFile(logfile.LogFile):
|
|||
_CHANNEL_LOG_NUM_TAIL_LINES = settings.CHANNEL_LOG_NUM_TAIL_LINES
|
||||
num_lines_to_append = _CHANNEL_LOG_NUM_TAIL_LINES
|
||||
|
||||
def rotate(self):
|
||||
def rotate(self, num_lines_to_append=None):
|
||||
"""
|
||||
Rotates our log file and appends some number of lines from
|
||||
the previous log to the start of the new one.
|
||||
"""
|
||||
append_tail = self.num_lines_to_append > 0
|
||||
append_tail = (num_lines_to_append
|
||||
if num_lines_to_append is not None
|
||||
else self.num_lines_to_append)
|
||||
if not append_tail:
|
||||
logfile.LogFile.rotate(self)
|
||||
return
|
||||
|
|
@ -472,6 +474,43 @@ def log_file(msg, filename="game.log"):
|
|||
deferToThread(callback, filehandle, msg).addErrback(errback)
|
||||
|
||||
|
||||
def log_file_exists(filename="game.log"):
|
||||
"""
|
||||
Determine if a log-file already exists.
|
||||
|
||||
Args:
|
||||
filename (str): The filename (within the log-dir).
|
||||
|
||||
Returns:
|
||||
bool: If the log file exists or not.
|
||||
|
||||
"""
|
||||
global _LOGDIR
|
||||
if not _LOGDIR:
|
||||
from django.conf import settings
|
||||
_LOGDIR = settings.LOG_DIR
|
||||
|
||||
filename = os.path.join(_LOGDIR, filename)
|
||||
return os.path.exists(filename)
|
||||
|
||||
|
||||
def rotate_log_file(filename="game.log", num_lines_to_append=None):
|
||||
"""
|
||||
Force-rotate a log-file, without
|
||||
|
||||
Args:
|
||||
filename (str): The log file, located in settings.LOG_DIR.
|
||||
num_lines_to_append (int, optional): Include N number of
|
||||
lines from previous file in new one. If `None`, use default.
|
||||
Set to 0 to include no lines.
|
||||
|
||||
"""
|
||||
if log_file_exists(filename):
|
||||
file_handle = _open_log_file(filename)
|
||||
if file_handle:
|
||||
file_handle.rotate(num_lines_to_append=num_lines_to_append)
|
||||
|
||||
|
||||
def tail_log_file(filename, offset, nlines, callback=None):
|
||||
"""
|
||||
Return the tail of the log file.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue