diff --git a/docs/source/Coding/Changelog.md b/docs/source/Coding/Changelog.md index c0cca561fb..1b10f9c4d9 100644 --- a/docs/source/Coding/Changelog.md +++ b/docs/source/Coding/Changelog.md @@ -218,6 +218,9 @@ Increase requirements: Django 4.1+, Twisted 22.10+ Python 3.9, 3.10, 3.11. Post - `utils.justify` now supports `align="a"` (absolute alignments. This keeps the given left indent but crops/fills to the width. Used in EvCells. - `EvTable` now supports passing `EvColumn`s as a list directly, (`EvTable(table=[colA,colB])`) +- Add `tags=` search criterion to `DefaultObject.search`. +- Add `AT_EXIT_TRAVERSE` signal, firing when an exit is traversed. +- Add integration between Evennia and Discord channels (PR by Inspector Cararacal) ## Evennia 0.9.5 diff --git a/docs/source/Components/Default-Commands.md b/docs/source/Components/Default-Commands.md index e930330d9f..8a19fc8523 100644 --- a/docs/source/Components/Default-Commands.md +++ b/docs/source/Components/Default-Commands.md @@ -1,6 +1,6 @@ # Default Commands -The full set of default Evennia commands currently contains 88 commands in 9 source +The full set of default Evennia commands currently contains 89 commands in 9 source files. Our policy for adding default commands is outlined [here](../Coding/Default-Command-Syntax.md). The [Commands](./Commands.md) documentation explains how Commands work as well as how to make new or customize existing ones. @@ -59,6 +59,7 @@ with [EvEditor](./EvEditor.md), flipping pages in [EvMore](./EvMore.md) or using - [**color**](CmdColorTest) (cmdset: [AccountCmdSet](AccountCmdSet), help-category: _General_) - [**connect** [co, con, conn]](CmdUnconnectedConnect) (cmdset: [UnloggedinCmdSet](UnloggedinCmdSet), help-category: _General_) - [**create** [cr, cre]](CmdUnconnectedCreate) (cmdset: [UnloggedinCmdSet](UnloggedinCmdSet), help-category: _General_) +- [**discord2chan** [discord]](CmdDiscord2Chan) (cmdset: [AccountCmdSet](AccountCmdSet), help-category: _Comms_) - [**drop**](CmdDrop) (cmdset: [CharacterCmdSet](CharacterCmdSet), help-category: _General_) - [**encoding** [encode]](CmdUnconnectedEncoding) (cmdset: [UnloggedinCmdSet](UnloggedinCmdSet), help-category: _General_) - [**get** [grab]](CmdGet) (cmdset: [CharacterCmdSet](CharacterCmdSet), help-category: _General_) diff --git a/docs/source/Setup/Settings-Default.md b/docs/source/Setup/Settings-Default.md index 1550dcee80..d01b01eb6a 100644 --- a/docs/source/Setup/Settings-Default.md +++ b/docs/source/Setup/Settings-Default.md @@ -893,6 +893,21 @@ GRAPEVINE_CHANNELS = ["gossip", "testing"] # them. These are secret and should thus be overridden in secret_settings file GRAPEVINE_CLIENT_ID = "" GRAPEVINE_CLIENT_SECRET = "" +# Discord (discord.com) is a popular communication service for many, especially +# for game communities. Evennia's channels can be connected to Discord channels +# and relay messages between Evennia and Discord. To use, you will need to create +# your own Discord application and bot. +# Discord also requires installing the pyopenssl library. +# Full step-by-step instructions are available in the official Evennia documentation. +DISCORD_ENABLED = False +# The Intents bitmask required by Discord bots to request particular API permissions. +# By default, this includes the basic guild status and message read/write flags. +DISCORD_BOT_INTENTS = 105985 +# The authentication token for the Discord bot. This should be kept secret and +# put in your secret_settings file. +DISCORD_BOT_TOKEN = None +# The account typeclass which the Evennia-side Discord relay bot will use. +DISCORD_BOT_CLASS = "evennia.accounts.bots.DiscordBot" ###################################################################### # Django web features diff --git a/docs/source/Setup/Setup-Overview.md b/docs/source/Setup/Setup-Overview.md index 6dda8a6106..f386b6d59f 100644 --- a/docs/source/Setup/Setup-Overview.md +++ b/docs/source/Setup/Setup-Overview.md @@ -26,8 +26,9 @@ Updating-Evennia Settings Settings-Default Choosing-a-Database -Channels-to-IRC +Channels-to-Discord Channels-to-Grapevine +Channels-to-IRC Channels-to-RSS Channels-to-Twitter ``` diff --git a/docs/source/api/evennia.server.portal.discord.md b/docs/source/api/evennia.server.portal.discord.md new file mode 100644 index 0000000000..14f84719c0 --- /dev/null +++ b/docs/source/api/evennia.server.portal.discord.md @@ -0,0 +1,10 @@ +```{eval-rst} +evennia.server.portal.discord +==================================== + +.. automodule:: evennia.server.portal.discord + :members: + :undoc-members: + :show-inheritance: + +``` \ No newline at end of file diff --git a/docs/source/api/evennia.server.portal.md b/docs/source/api/evennia.server.portal.md index 28004c1f15..a59eb5f70d 100644 --- a/docs/source/api/evennia.server.portal.md +++ b/docs/source/api/evennia.server.portal.md @@ -14,6 +14,7 @@ evennia.server.portal evennia.server.portal.amp evennia.server.portal.amp_server + evennia.server.portal.discord evennia.server.portal.grapevine evennia.server.portal.irc evennia.server.portal.mccp diff --git a/evennia/accounts/bots.py b/evennia/accounts/bots.py index 8f157c3953..c2ebbf2619 100644 --- a/evennia/accounts/bots.py +++ b/evennia/accounts/bots.py @@ -8,7 +8,6 @@ import time from django.conf import settings from django.utils.translation import gettext as _ - from evennia.accounts.accounts import DefaultAccount from evennia.scripts.scripts import DefaultScript from evennia.utils import logger, search, utils @@ -566,8 +565,9 @@ class GrapevineBot(Bot): class DiscordBot(Bot): """ - Discord bot relay. You will need to set up your own bot (https://discord.com/developers/applications) - and add the bot token as `DISCORD_BOT_TOKEN` to `secret_settings.py` to use + Discord bot relay. You will need to set up your own bot + (https://discord.com/developers/applications) and add the bot token as `DISCORD_BOT_TOKEN` to + `secret_settings.py` to use """ factory_path = "evennia.server.portal.discord.DiscordWebsocketServerFactory" @@ -575,9 +575,11 @@ class DiscordBot(Bot): def at_init(self): """ Load required channels back into memory + """ if channel_links := self.db.channels: - # this attribute contains a list of evennia<->discord links in the form of ("evennia_channel", "discord_chan_id") + # this attribute contains a list of evennia<->discord links in the form + # of ("evennia_channel", "discord_chan_id") # grab Evennia channels, cache and connect channel_set = {evchan for evchan, dcid in channel_links} self.ndb.ev_channels = {} @@ -602,7 +604,8 @@ class DiscordBot(Bot): channel.connect(self) elif channel_links := self.db.channels: - # this attribute contains a list of evennia<->discord links in the form of ("evennia_channel", "discord_chan_id") + # this attribute contains a list of evennia<->discord links in the form + # of ("evennia_channel", "discord_chan_id") # grab Evennia channels, cache and connect channel_set = {evchan for evchan, dcid in channel_links} self.ndb.ev_channels = {} @@ -627,6 +630,7 @@ class DiscordBot(Bot): Called by the Channel just before passing a message into `channel_msg`. We overload this to set the channel tag prefix. + """ kwargs["no_prefix"] = not self.db.tag_channel return super().at_pre_channel_msg(message, channel, senders=senders, **kwargs) @@ -663,7 +667,7 @@ class DiscordBot(Bot): sender (tuple) - The Discord info for the sender in the form (id, nickname) Keyword args: - kwargs (optional) - Unused by default, but can carry additional data from the protocol. + **kwargs (optional) - Unused by default, but can carry additional data from the protocol. """ pass @@ -672,17 +676,20 @@ class DiscordBot(Bot): self, message, to_channel, sender=None, from_channel=None, from_server=None, **kwargs ): """ - Formats and sends a Discord -> Evennia message. Called when the Discord bot receives a channel message on Discord. + Formats and sends a Discord -> Evennia message. Called when the Discord bot receives a + channel message on Discord. Args: message (str) - Incoming text from Discord. to_channel (Channel) - The Evennia channel receiving the message Keyword args: - sender (tuple) - The Discord info for the sender in the form (id, nickname) + sender (tuple) - The Discord info for the sender in the form `(id, nickname)` from_channel (str) - The Discord channel name from_server (str) - The Discord server name - kwargs - Any additional keywords. Unused by default, but available for adding additional flags or parameters. + kwargs - Any additional keywords. Unused by default, but available for adding additional + flags or parameters. + """ tag_str = "" diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 81ef7fd7c6..e47941709f 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -6,6 +6,7 @@ import re from django.conf import settings from django.core.paginator import Paginator from django.db.models import Max, Min, Q + from evennia import InterruptCommand from evennia.commands.cmdhandler import get_and_merge_cmdsets from evennia.locks.lockhandler import LockException diff --git a/evennia/objects/manager.py b/evennia/objects/manager.py index 81e61482a7..2957e6aa42 100644 --- a/evennia/objects/manager.py +++ b/evennia/objects/manager.py @@ -6,6 +6,7 @@ import re from django.conf import settings from django.db.models import Q from django.db.models.fields import exceptions + from evennia.server import signals from evennia.typeclasses.managers import TypeclassManager, TypedObjectManager from evennia.utils.utils import ( diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index dc17f0c717..085ae8767c 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -13,6 +13,7 @@ from collections import defaultdict import inflect from django.conf import settings from django.utils.translation import gettext as _ + from evennia.commands import cmdset from evennia.commands.cmdsethandler import CmdSetHandler from evennia.objects.manager import ObjectManager diff --git a/evennia/server/portal/discord.py b/evennia/server/portal/discord.py index 3605450851..6fa6673236 100644 --- a/evennia/server/portal/discord.py +++ b/evennia/server/portal/discord.py @@ -10,8 +10,8 @@ added to `server/conf/secret_settings.py` as your DISCORD_BOT_TOKEN """ import json import os -from random import random from io import BytesIO +from random import random from autobahn.twisted.websocket import ( WebSocketClientFactory, diff --git a/evennia/server/signals.py b/evennia/server/signals.py index 2fcc4b6d67..728825a7df 100644 --- a/evennia/server/signals.py +++ b/evennia/server/signals.py @@ -95,9 +95,9 @@ SIGNAL_EXIT_TRAVERSED = Signal() from django.core.signals import request_finished # " ends. from django.core.signals import request_started # Sent when HTTP request begins. -from django.db.backends.signals import ( +from django.db.backends.signals import ( # Sent when making initial connection to database connection_created, -) # Sent when making initial connection to database +) from django.db.models.signals import m2m_changed # Sent when a ManyToManyField changes. from django.db.models.signals import post_delete # after " from django.db.models.signals import post_init # end @@ -105,9 +105,15 @@ from django.db.models.signals import post_migrate # after " from django.db.models.signals import post_save # after " from django.db.models.signals import pre_delete # Sent before an object is deleted. from django.db.models.signals import pre_migrate # Sent before migration starts -from django.db.models.signals import pre_save # Sent before a typeclass' .save is called. from django.db.models.signals import ( + pre_save, # Sent before a typeclass' .save is called. +) +from django.db.models.signals import ( # Sent at start of typeclass __init__ (before at_init) pre_init, -) # Sent at start of typeclass __init__ (before at_init) -from django.test.signals import setting_changed # Sent when setting changes from override -from django.test.signals import template_rendered # Sent when test system renders template +) +from django.test.signals import ( + setting_changed, # Sent when setting changes from override +) +from django.test.signals import ( + template_rendered, # Sent when test system renders template +) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 0e238a14f8..fee012eaed 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -8,6 +8,7 @@ import shlex from django.db.models import Count, ExpressionWrapper, F, FloatField, Q from django.db.models.functions import Cast + from evennia.typeclasses.attributes import Attribute from evennia.typeclasses.tags import Tag from evennia.utils import idmapper