Fix long-standing issue with user updates not dispatching properly.
This fix is long coming. For a long time due to the addition of a global user cache, the on_member_update event would only have the updated user in the very first dispatch due to a quirk in the reference only being updated once. In order to fix this issue two things had to change: 1. There had to be a new event, `on_user_update` to complement the equivalent member event. 2. Unnecessary copies of User had to be removed to compensate for the performance hit from the diffing. While doing these two fixes I also re-evaluated some more unnecessary copies done during the PRESENCE_UPDATE to add member case while fetch_offline_members=False is set or due to chunking issues. The number of copies was brought down from 2 to 1, discounting the original Member creation. Unsure on the benefits of this one, however. N.B: this doesn't change the pre-existing behaviour of on_member_update
This commit is contained in:
		@@ -189,6 +189,17 @@ class Member(discord.abc.Messageable, _BaseUser):
 | 
			
		||||
        }
 | 
			
		||||
        return cls(data=data, guild=message.guild, state=message._state)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def _from_presence_update(cls, *, data, guild, state):
 | 
			
		||||
        clone = cls(data=data, guild=guild, state=state)
 | 
			
		||||
        to_return = cls(data=data, guild=guild, state=state)
 | 
			
		||||
        to_return._client_status = {
 | 
			
		||||
            key: value
 | 
			
		||||
            for key, value in data.get('client_status', {}).items()
 | 
			
		||||
        }
 | 
			
		||||
        to_return._client_status[None] = data['status']
 | 
			
		||||
        return to_return, clone
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def _copy(cls, member):
 | 
			
		||||
        self = cls.__new__(cls) # to bypass __init__
 | 
			
		||||
@@ -200,7 +211,10 @@ class Member(discord.abc.Messageable, _BaseUser):
 | 
			
		||||
        self.nick = member.nick
 | 
			
		||||
        self.activities = member.activities
 | 
			
		||||
        self._state = member._state
 | 
			
		||||
        self._user = User._copy(member._user)
 | 
			
		||||
 | 
			
		||||
        # Reference will not be copied unless necessary by PRESENCE_UPDATE
 | 
			
		||||
        # See below
 | 
			
		||||
        self._user = member._user
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    async def _get_channel(self):
 | 
			
		||||
@@ -230,9 +244,15 @@ class Member(discord.abc.Messageable, _BaseUser):
 | 
			
		||||
 | 
			
		||||
        if len(user) > 1:
 | 
			
		||||
            u = self._user
 | 
			
		||||
            u.name = user.get('username', u.name)
 | 
			
		||||
            u.avatar = user.get('avatar', u.avatar)
 | 
			
		||||
            u.discriminator = user.get('discriminator', u.discriminator)
 | 
			
		||||
            original = (u.name, u.avatar, u.discriminator)
 | 
			
		||||
            # These keys seem to always be available
 | 
			
		||||
            modified = (user['username'], user['avatar'], user['discriminator'])
 | 
			
		||||
            if original != modified:
 | 
			
		||||
                to_return = User._copy(self._user)
 | 
			
		||||
                u.name, u.avatar, u.discriminator = modified
 | 
			
		||||
                # Signal to dispatch on_user_update
 | 
			
		||||
                return to_return, u
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def status(self):
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user