merge conflict fix
This commit is contained in:
commit
571ddb5a3e
@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
import sys
|
||||||
import copy
|
import copy
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
@ -169,7 +170,7 @@ class _Overwrites:
|
|||||||
self.id = kwargs.pop('id')
|
self.id = kwargs.pop('id')
|
||||||
self.allow = kwargs.pop('allow', 0)
|
self.allow = kwargs.pop('allow', 0)
|
||||||
self.deny = kwargs.pop('deny', 0)
|
self.deny = kwargs.pop('deny', 0)
|
||||||
self.type = kwargs.pop('type')
|
self.type = sys.intern(kwargs.pop('type'))
|
||||||
|
|
||||||
def _asdict(self):
|
def _asdict(self):
|
||||||
return {
|
return {
|
||||||
@ -933,7 +934,6 @@ class Messageable(metaclass=abc.ABCMeta):
|
|||||||
"""
|
"""
|
||||||
return Typing(self)
|
return Typing(self)
|
||||||
|
|
||||||
@utils.deprecated('fetch_message_fast')
|
|
||||||
async def fetch_message(self, id):
|
async def fetch_message(self, id):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
@ -941,8 +941,6 @@ class Messageable(metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
This can only be used by bot accounts.
|
This can only be used by bot accounts.
|
||||||
|
|
||||||
Prefer using :meth:`fetch_message_fast`.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
------------
|
------------
|
||||||
id: :class:`int`
|
id: :class:`int`
|
||||||
@ -967,40 +965,6 @@ class Messageable(metaclass=abc.ABCMeta):
|
|||||||
data = await self._state.http.get_message(channel.id, id)
|
data = await self._state.http.get_message(channel.id, id)
|
||||||
return self._state.create_message(channel=channel, data=data)
|
return self._state.create_message(channel=channel, data=data)
|
||||||
|
|
||||||
async def fetch_message_fast(self, id):
|
|
||||||
"""|coro|
|
|
||||||
|
|
||||||
Retrieves a single :class:`~discord.Message` from the destination, using
|
|
||||||
the history endpoint.
|
|
||||||
|
|
||||||
.. versionadded:: 1.5
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
------------
|
|
||||||
id: :class:`int`
|
|
||||||
The message ID to look for.
|
|
||||||
|
|
||||||
Raises
|
|
||||||
--------
|
|
||||||
~discord.NotFound
|
|
||||||
The specified channel was not found.
|
|
||||||
~discord.Forbidden
|
|
||||||
You do not have permissions to get channel message history.
|
|
||||||
~discord.HTTPException
|
|
||||||
The request to get message history failed.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
--------
|
|
||||||
Optional[:class:`~discord.Message`]
|
|
||||||
The message asked for, or None if there is no match.
|
|
||||||
"""
|
|
||||||
|
|
||||||
channel = await self._get_channel()
|
|
||||||
data = await self._state.http.logs_from(channel.id, limit=1, around=id)
|
|
||||||
if data and int(data[0]['id']) == id:
|
|
||||||
return self._state.create_message(channel=channel, data=data[0])
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def pins(self):
|
async def pins(self):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
|
@ -142,9 +142,14 @@ class Client:
|
|||||||
shard_count: Optional[:class:`int`]
|
shard_count: Optional[:class:`int`]
|
||||||
The total number of shards.
|
The total number of shards.
|
||||||
intents: :class:`Intents`
|
intents: :class:`Intents`
|
||||||
A list of intents that you want to enable for the session. This is a way of
|
The intents that you want to enable for the session. This is a way of
|
||||||
disabling and enabling certain gateway events from triggering and being sent.
|
disabling and enabling certain gateway events from triggering and being sent.
|
||||||
Currently, if no intents are passed then you will receive all data.
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
member_cache_flags: :class:`MemberCacheFlags`
|
||||||
|
Allows for finer control over how the library caches members.
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
fetch_offline_members: :class:`bool`
|
fetch_offline_members: :class:`bool`
|
||||||
Indicates if :func:`.on_ready` should be delayed to fetch all offline
|
Indicates if :func:`.on_ready` should be delayed to fetch all offline
|
||||||
members from the guilds the client belongs to. If this is ``False``\, then
|
members from the guilds the client belongs to. If this is ``False``\, then
|
||||||
@ -565,6 +570,8 @@ class Client:
|
|||||||
# sometimes, discord sends us 1000 for unknown reasons so we should reconnect
|
# sometimes, discord sends us 1000 for unknown reasons so we should reconnect
|
||||||
# regardless and rely on is_closed instead
|
# regardless and rely on is_closed instead
|
||||||
if isinstance(exc, ConnectionClosed):
|
if isinstance(exc, ConnectionClosed):
|
||||||
|
if exc.code == 4014:
|
||||||
|
raise PrivilegedIntentsRequired(exc.shard_id) from None
|
||||||
if exc.code != 1000:
|
if exc.code != 1000:
|
||||||
await self.close()
|
await self.close()
|
||||||
raise
|
raise
|
||||||
|
@ -51,7 +51,7 @@ __all__ = (
|
|||||||
'Theme',
|
'Theme',
|
||||||
'WebhookType',
|
'WebhookType',
|
||||||
'ExpireBehaviour',
|
'ExpireBehaviour',
|
||||||
'ExpireBehavior'
|
'ExpireBehavior',
|
||||||
)
|
)
|
||||||
|
|
||||||
def _create_value_cls(name):
|
def _create_value_cls(name):
|
||||||
|
@ -175,3 +175,27 @@ class ConnectionClosed(ClientException):
|
|||||||
self.reason = ''
|
self.reason = ''
|
||||||
self.shard_id = shard_id
|
self.shard_id = shard_id
|
||||||
super().__init__('Shard ID %s WebSocket closed with %s' % (self.shard_id, self.code))
|
super().__init__('Shard ID %s WebSocket closed with %s' % (self.shard_id, self.code))
|
||||||
|
|
||||||
|
class PrivilegedIntentsRequired(ClientException):
|
||||||
|
"""Exception that's thrown when the gateway is requesting privileged intents
|
||||||
|
but they're not ticked in the developer page yet.
|
||||||
|
|
||||||
|
Go to https://discord.com/developers/applications/ and enable the intents
|
||||||
|
that are required. Currently these are as follows:
|
||||||
|
|
||||||
|
- :attr:`Intents.members`
|
||||||
|
- :attr:`Intents.presences`
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
shard_id: Optional[:class:`int`]
|
||||||
|
The shard ID that got closed if applicable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, shard_id):
|
||||||
|
self.shard_id = shard_id
|
||||||
|
msg = 'Shard ID %s is requesting privileged intents that have not been explicitly enabled in the ' \
|
||||||
|
'developer portal. It is recommended to go to https://discord.com/developers/applications/ ' \
|
||||||
|
'and explicitly enable the privileged intents within your application\'s page. If this is not ' \
|
||||||
|
'possible, then consider disabling the privileged intents instead.'
|
||||||
|
super().__init__(msg % shard_id)
|
||||||
|
125
discord/flags.py
125
discord/flags.py
@ -31,6 +31,7 @@ __all__ = (
|
|||||||
'MessageFlags',
|
'MessageFlags',
|
||||||
'PublicUserFlags',
|
'PublicUserFlags',
|
||||||
'Intents',
|
'Intents',
|
||||||
|
'MemberCacheFlags',
|
||||||
)
|
)
|
||||||
|
|
||||||
class flag_value:
|
class flag_value:
|
||||||
@ -651,3 +652,127 @@ class Intents(BaseFlags):
|
|||||||
- :func:`on_typing` (only for DMs)
|
- :func:`on_typing` (only for DMs)
|
||||||
"""
|
"""
|
||||||
return 1 << 14
|
return 1 << 14
|
||||||
|
|
||||||
|
@fill_with_flags()
|
||||||
|
class MemberCacheFlags(BaseFlags):
|
||||||
|
"""Controls the library's cache policy when it comes to members.
|
||||||
|
|
||||||
|
This allows for finer grained control over what members are cached.
|
||||||
|
For more information, check :attr:`Client.member_cache_flags`. Note
|
||||||
|
that the bot's own member is always cached.
|
||||||
|
|
||||||
|
Due to a quirk in how Discord works, in order to ensure proper cleanup
|
||||||
|
of cache resources it is recommended to have :attr:`Intents.members`
|
||||||
|
enabled. Otherwise the library cannot know when a member leaves a guild and
|
||||||
|
is thus unable to cleanup after itself.
|
||||||
|
|
||||||
|
To construct an object you can pass keyword arguments denoting the flags
|
||||||
|
to enable or disable.
|
||||||
|
|
||||||
|
The default value is all flags enabled.
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
|
||||||
|
.. container:: operations
|
||||||
|
|
||||||
|
.. describe:: x == y
|
||||||
|
|
||||||
|
Checks if two flags are equal.
|
||||||
|
.. describe:: x != y
|
||||||
|
|
||||||
|
Checks if two flags are not equal.
|
||||||
|
.. describe:: hash(x)
|
||||||
|
|
||||||
|
Return the flag's hash.
|
||||||
|
.. describe:: iter(x)
|
||||||
|
|
||||||
|
Returns an iterator of ``(name, value)`` pairs. This allows it
|
||||||
|
to be, for example, constructed as a dict or a list of pairs.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
value: :class:`int`
|
||||||
|
The raw value. You should query flags via the properties
|
||||||
|
rather than using this raw value.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
bits = max(self.VALID_FLAGS.values()).bit_length()
|
||||||
|
self.value = (1 << bits) - 1
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
if key not in self.VALID_FLAGS:
|
||||||
|
raise TypeError('%r is not a valid flag name.' % key)
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all(cls):
|
||||||
|
"""A factory method that creates a :class:`MemberCacheFlags` with everything enabled."""
|
||||||
|
bits = max(cls.VALID_FLAGS.values()).bit_length()
|
||||||
|
value = (1 << bits) - 1
|
||||||
|
self = cls.__new__(cls)
|
||||||
|
self.value = value
|
||||||
|
return self
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def none(cls):
|
||||||
|
"""A factory method that creates a :class:`MemberCacheFlags` with everything disabled."""
|
||||||
|
self = cls.__new__(cls)
|
||||||
|
self.value = self.DEFAULT_VALUE
|
||||||
|
return self
|
||||||
|
|
||||||
|
@flag_value
|
||||||
|
def online(self):
|
||||||
|
""":class:`bool`: Whether to cache members with a status.
|
||||||
|
|
||||||
|
For example, members that are part of the initial ``GUILD_CREATE``
|
||||||
|
or become online at a later point. This requires :attr:`Intents.presences`.
|
||||||
|
|
||||||
|
Members that go offline are no longer cached.
|
||||||
|
"""
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@flag_value
|
||||||
|
def voice(self):
|
||||||
|
""":class:`bool`: Whether to cache members that are in voice.
|
||||||
|
|
||||||
|
This requires :attr:`Intents.voice_states`.
|
||||||
|
|
||||||
|
Members that leave voice are no longer cached.
|
||||||
|
"""
|
||||||
|
return 2
|
||||||
|
|
||||||
|
@flag_value
|
||||||
|
def joined(self):
|
||||||
|
""":class:`bool`: Whether to cache members that joined the guild
|
||||||
|
or are chunked as part of the initial log in flow.
|
||||||
|
|
||||||
|
This requires :attr:`Intents.members`.
|
||||||
|
|
||||||
|
Members that leave the guild are no longer cached.
|
||||||
|
"""
|
||||||
|
return 4
|
||||||
|
|
||||||
|
def _verify_intents(self, intents):
|
||||||
|
if self.online and not intents.presences:
|
||||||
|
raise ValueError('MemberCacheFlags.online requires Intents.presences enabled')
|
||||||
|
|
||||||
|
if self.voice and not intents.voice_states:
|
||||||
|
raise ValueError('MemberCacheFlags.voice requires Intents.voice_states')
|
||||||
|
|
||||||
|
if self.joined and not intents.members:
|
||||||
|
raise ValueError('MemberCacheFlags.joined requires Intents.members')
|
||||||
|
|
||||||
|
if not self.joined and self.voice and self.online:
|
||||||
|
msg = 'MemberCacheFlags.voice and MemberCacheFlags.online require MemberCacheFlags.joined ' \
|
||||||
|
'to properly evict members from the cache.'
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _voice_only(self):
|
||||||
|
return self.value == 2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _online_only(self):
|
||||||
|
return self.value == 1
|
@ -305,11 +305,12 @@ class Guild(Hashable):
|
|||||||
self._rules_channel_id = utils._get_as_snowflake(guild, 'rules_channel_id')
|
self._rules_channel_id = utils._get_as_snowflake(guild, 'rules_channel_id')
|
||||||
self._public_updates_channel_id = utils._get_as_snowflake(guild, 'public_updates_channel_id')
|
self._public_updates_channel_id = utils._get_as_snowflake(guild, 'public_updates_channel_id')
|
||||||
|
|
||||||
cache_members = self._state._cache_members
|
cache_online_members = self._state._member_cache_flags.online
|
||||||
|
cache_joined = self._state._member_cache_flags.joined
|
||||||
self_id = self._state.self_id
|
self_id = self._state.self_id
|
||||||
for mdata in guild.get('members', []):
|
for mdata in guild.get('members', []):
|
||||||
member = Member(data=mdata, guild=self, state=state)
|
member = Member(data=mdata, guild=self, state=state)
|
||||||
if cache_members or member.id == self_id:
|
if cache_joined or (cache_online_members and member.raw_status != 'offline') or member.id == self_id:
|
||||||
self._add_member(member)
|
self._add_member(member)
|
||||||
|
|
||||||
self._sync(guild)
|
self._sync(guild)
|
||||||
|
@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
import sys
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
import discord.abc
|
import discord.abc
|
||||||
@ -215,10 +216,10 @@ class Member(discord.abc.Messageable, _BaseUser):
|
|||||||
clone = cls(data=data, guild=guild, state=state)
|
clone = cls(data=data, guild=guild, state=state)
|
||||||
to_return = cls(data=data, guild=guild, state=state)
|
to_return = cls(data=data, guild=guild, state=state)
|
||||||
to_return._client_status = {
|
to_return._client_status = {
|
||||||
key: value
|
sys.intern(key): sys.intern(value)
|
||||||
for key, value in data.get('client_status', {}).items()
|
for key, value in data.get('client_status', {}).items()
|
||||||
}
|
}
|
||||||
to_return._client_status[None] = data['status']
|
to_return._client_status[None] = sys.intern(data['status'])
|
||||||
return to_return, clone
|
return to_return, clone
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -260,10 +261,10 @@ class Member(discord.abc.Messageable, _BaseUser):
|
|||||||
def _presence_update(self, data, user):
|
def _presence_update(self, data, user):
|
||||||
self.activities = tuple(map(create_activity, data.get('activities', [])))
|
self.activities = tuple(map(create_activity, data.get('activities', [])))
|
||||||
self._client_status = {
|
self._client_status = {
|
||||||
key: value
|
sys.intern(key): sys.intern(value)
|
||||||
for key, value in data.get('client_status', {}).items()
|
for key, value in data.get('client_status', {}).items()
|
||||||
}
|
}
|
||||||
self._client_status[None] = data['status']
|
self._client_status[None] = sys.intern(data['status'])
|
||||||
|
|
||||||
if len(user) > 1:
|
if len(user) > 1:
|
||||||
return self._update_inner_user(user)
|
return self._update_inner_user(user)
|
||||||
@ -285,6 +286,14 @@ class Member(discord.abc.Messageable, _BaseUser):
|
|||||||
""":class:`Status`: The member's overall status. If the value is unknown, then it will be a :class:`str` instead."""
|
""":class:`Status`: The member's overall status. If the value is unknown, then it will be a :class:`str` instead."""
|
||||||
return try_enum(Status, self._client_status[None])
|
return try_enum(Status, self._client_status[None])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raw_status(self):
|
||||||
|
""":class:`str`: The member's overall status as a string value.
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
"""
|
||||||
|
return self._client_status[None]
|
||||||
|
|
||||||
@status.setter
|
@status.setter
|
||||||
def status(self, value):
|
def status(self, value):
|
||||||
# internal use only
|
# internal use only
|
||||||
|
@ -34,7 +34,15 @@ from .state import AutoShardedConnectionState
|
|||||||
from .client import Client
|
from .client import Client
|
||||||
from .backoff import ExponentialBackoff
|
from .backoff import ExponentialBackoff
|
||||||
from .gateway import *
|
from .gateway import *
|
||||||
from .errors import ClientException, InvalidArgument, HTTPException, GatewayNotFound, ConnectionClosed
|
from .errors import (
|
||||||
|
ClientException,
|
||||||
|
InvalidArgument,
|
||||||
|
HTTPException,
|
||||||
|
GatewayNotFound,
|
||||||
|
ConnectionClosed,
|
||||||
|
PrivilegedIntentsRequired,
|
||||||
|
)
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .enums import Status
|
from .enums import Status
|
||||||
|
|
||||||
@ -125,6 +133,9 @@ class Shard:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(e, ConnectionClosed):
|
if isinstance(e, ConnectionClosed):
|
||||||
|
if e.code == 4014:
|
||||||
|
self._queue_put(EventItem(EventType.terminate, self, PrivilegedIntentsRequired(self.id)))
|
||||||
|
return
|
||||||
if e.code != 1000:
|
if e.code != 1000:
|
||||||
self._queue_put(EventItem(EventType.close, self, e))
|
self._queue_put(EventItem(EventType.close, self, e))
|
||||||
return
|
return
|
||||||
@ -407,8 +418,11 @@ class AutoShardedClient(Client):
|
|||||||
item = await self.__queue.get()
|
item = await self.__queue.get()
|
||||||
if item.type == EventType.close:
|
if item.type == EventType.close:
|
||||||
await self.close()
|
await self.close()
|
||||||
if isinstance(item.error, ConnectionClosed) and item.error.code != 1000:
|
if isinstance(item.error, ConnectionClosed):
|
||||||
raise item.error
|
if item.error.code != 1000:
|
||||||
|
raise item.error
|
||||||
|
if item.error.code == 4014:
|
||||||
|
raise PrivilegedIntentsRequired(item.shard.id) from None
|
||||||
return
|
return
|
||||||
elif item.type in (EventType.identify, EventType.resume):
|
elif item.type in (EventType.identify, EventType.resume):
|
||||||
await item.shard.reidentify(item.error)
|
await item.shard.reidentify(item.error)
|
||||||
|
@ -51,7 +51,7 @@ from .member import Member
|
|||||||
from .role import Role
|
from .role import Role
|
||||||
from .enums import ChannelType, try_enum, Status
|
from .enums import ChannelType, try_enum, Status
|
||||||
from . import utils
|
from . import utils
|
||||||
from .flags import Intents
|
from .flags import Intents, MemberCacheFlags
|
||||||
from .embeds import Embed
|
from .embeds import Embed
|
||||||
from .object import Object
|
from .object import Object
|
||||||
from .invite import Invite
|
from .invite import Invite
|
||||||
@ -110,8 +110,6 @@ class ConnectionState:
|
|||||||
raise TypeError('allowed_mentions parameter must be AllowedMentions')
|
raise TypeError('allowed_mentions parameter must be AllowedMentions')
|
||||||
|
|
||||||
self.allowed_mentions = allowed_mentions
|
self.allowed_mentions = allowed_mentions
|
||||||
# Only disable cache if both fetch_offline and guild_subscriptions are off.
|
|
||||||
self._cache_members = (self._fetch_offline or self.guild_subscriptions)
|
|
||||||
self._chunk_requests = []
|
self._chunk_requests = []
|
||||||
|
|
||||||
activity = options.get('activity', None)
|
activity = options.get('activity', None)
|
||||||
@ -136,6 +134,19 @@ class ConnectionState:
|
|||||||
if not intents.members and self._fetch_offline:
|
if not intents.members and self._fetch_offline:
|
||||||
raise ValueError('Intents.members has be enabled to fetch offline members.')
|
raise ValueError('Intents.members has be enabled to fetch offline members.')
|
||||||
|
|
||||||
|
else:
|
||||||
|
intents = Intents()
|
||||||
|
|
||||||
|
cache_flags = options.get('member_cache_flags', None)
|
||||||
|
if cache_flags is None:
|
||||||
|
cache_flags = MemberCacheFlags.all()
|
||||||
|
else:
|
||||||
|
if not isinstance(cache_flags, MemberCacheFlags):
|
||||||
|
raise TypeError('member_cache_flags parameter must be MemberCacheFlags not %r' % type(cache_flags))
|
||||||
|
|
||||||
|
cache_flags._verify_intents(intents)
|
||||||
|
|
||||||
|
self._member_cache_flags = cache_flags
|
||||||
self._activity = activity
|
self._activity = activity
|
||||||
self._status = status
|
self._status = status
|
||||||
self._intents = intents
|
self._intents = intents
|
||||||
@ -558,6 +569,7 @@ class ConnectionState:
|
|||||||
user = data['user']
|
user = data['user']
|
||||||
member_id = int(user['id'])
|
member_id = int(user['id'])
|
||||||
member = guild.get_member(member_id)
|
member = guild.get_member(member_id)
|
||||||
|
flags = self._member_cache_flags
|
||||||
if member is None:
|
if member is None:
|
||||||
if 'username' not in user:
|
if 'username' not in user:
|
||||||
# sometimes we receive 'incomplete' member data post-removal.
|
# sometimes we receive 'incomplete' member data post-removal.
|
||||||
@ -565,13 +577,17 @@ class ConnectionState:
|
|||||||
return
|
return
|
||||||
|
|
||||||
member, old_member = Member._from_presence_update(guild=guild, data=data, state=self)
|
member, old_member = Member._from_presence_update(guild=guild, data=data, state=self)
|
||||||
guild._add_member(member)
|
if flags.online or (flags._online_only and member.raw_status != 'offline'):
|
||||||
|
guild._add_member(member)
|
||||||
else:
|
else:
|
||||||
old_member = Member._copy(member)
|
old_member = Member._copy(member)
|
||||||
user_update = member._presence_update(data=data, user=user)
|
user_update = member._presence_update(data=data, user=user)
|
||||||
if user_update:
|
if user_update:
|
||||||
self.dispatch('user_update', user_update[0], user_update[1])
|
self.dispatch('user_update', user_update[0], user_update[1])
|
||||||
|
|
||||||
|
if flags._online_only and member.raw_status == 'offline':
|
||||||
|
guild._remove_member(member)
|
||||||
|
|
||||||
self.dispatch('member_update', old_member, member)
|
self.dispatch('member_update', old_member, member)
|
||||||
|
|
||||||
def parse_user_update(self, data):
|
def parse_user_update(self, data):
|
||||||
@ -691,7 +707,7 @@ class ConnectionState:
|
|||||||
return
|
return
|
||||||
|
|
||||||
member = Member(guild=guild, data=data, state=self)
|
member = Member(guild=guild, data=data, state=self)
|
||||||
if self._cache_members:
|
if self._member_cache_flags.joined:
|
||||||
guild._add_member(member)
|
guild._add_member(member)
|
||||||
guild._member_count += 1
|
guild._member_count += 1
|
||||||
self.dispatch('member_join', member)
|
self.dispatch('member_join', member)
|
||||||
@ -754,7 +770,7 @@ class ConnectionState:
|
|||||||
return self._add_guild_from_data(data)
|
return self._add_guild_from_data(data)
|
||||||
|
|
||||||
async def chunk_guild(self, guild, *, wait=True, cache=None):
|
async def chunk_guild(self, guild, *, wait=True, cache=None):
|
||||||
cache = cache or self._cache_members
|
cache = cache or self._member_cache_flags.joined
|
||||||
future = self.loop.create_future()
|
future = self.loop.create_future()
|
||||||
request = ChunkRequest(guild.id, future, self._get_guild, cache=cache)
|
request = ChunkRequest(guild.id, future, self._get_guild, cache=cache)
|
||||||
self._chunk_requests.append(request)
|
self._chunk_requests.append(request)
|
||||||
@ -920,6 +936,7 @@ class ConnectionState:
|
|||||||
def parse_voice_state_update(self, data):
|
def parse_voice_state_update(self, data):
|
||||||
guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
|
guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
|
||||||
channel_id = utils._get_as_snowflake(data, 'channel_id')
|
channel_id = utils._get_as_snowflake(data, 'channel_id')
|
||||||
|
flags = self._member_cache_flags
|
||||||
if guild is not None:
|
if guild is not None:
|
||||||
if int(data['user_id']) == self.user.id:
|
if int(data['user_id']) == self.user.id:
|
||||||
voice = self._get_voice_client(guild.id)
|
voice = self._get_voice_client(guild.id)
|
||||||
@ -930,6 +947,13 @@ class ConnectionState:
|
|||||||
|
|
||||||
member, before, after = guild._update_voice_state(data, channel_id)
|
member, before, after = guild._update_voice_state(data, channel_id)
|
||||||
if member is not None:
|
if member is not None:
|
||||||
|
if flags.voice:
|
||||||
|
if channel_id is None and flags.value == MemberCacheFlags.voice.flag:
|
||||||
|
# Only remove from cache iff we only have the voice flag enabled
|
||||||
|
guild._remove_member(member)
|
||||||
|
else:
|
||||||
|
guild._add_member(member)
|
||||||
|
|
||||||
self.dispatch('voice_state_update', member, before, after)
|
self.dispatch('voice_state_update', member, before, after)
|
||||||
else:
|
else:
|
||||||
log.debug('VOICE_STATE_UPDATE referencing an unknown member ID: %s. Discarding.', data['user_id'])
|
log.debug('VOICE_STATE_UPDATE referencing an unknown member ID: %s. Discarding.', data['user_id'])
|
||||||
|
15
docs/api.rst
15
docs/api.rst
@ -2803,6 +2803,18 @@ AllowedMentions
|
|||||||
.. autoclass:: AllowedMentions
|
.. autoclass:: AllowedMentions
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Intents
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: Intents
|
||||||
|
:members:
|
||||||
|
|
||||||
|
MemberCacheFlags
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: MemberCacheFlags
|
||||||
|
:members:
|
||||||
|
|
||||||
File
|
File
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
@ -2912,6 +2924,8 @@ The following exceptions are thrown by the library.
|
|||||||
|
|
||||||
.. autoexception:: ConnectionClosed
|
.. autoexception:: ConnectionClosed
|
||||||
|
|
||||||
|
.. autoexception:: PrivilegedIntentsRequired
|
||||||
|
|
||||||
.. autoexception:: discord.opus.OpusError
|
.. autoexception:: discord.opus.OpusError
|
||||||
|
|
||||||
.. autoexception:: discord.opus.OpusNotLoaded
|
.. autoexception:: discord.opus.OpusNotLoaded
|
||||||
@ -2928,6 +2942,7 @@ Exception Hierarchy
|
|||||||
- :exc:`InvalidArgument`
|
- :exc:`InvalidArgument`
|
||||||
- :exc:`LoginFailure`
|
- :exc:`LoginFailure`
|
||||||
- :exc:`ConnectionClosed`
|
- :exc:`ConnectionClosed`
|
||||||
|
- :exc:`PrivilegedIntentsRequired`
|
||||||
- :exc:`NoMoreItems`
|
- :exc:`NoMoreItems`
|
||||||
- :exc:`GatewayNotFound`
|
- :exc:`GatewayNotFound`
|
||||||
- :exc:`HTTPException`
|
- :exc:`HTTPException`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user