Skip to content

Commit

Permalink
v3.6.0 changes
Browse files Browse the repository at this point in the history
v3.6.0 changes
  • Loading branch information
Terbau committed May 31, 2021
2 parents c64d725 + 6b8c3d2 commit 09f7828
Show file tree
Hide file tree
Showing 11 changed files with 741 additions and 112 deletions.
45 changes: 41 additions & 4 deletions docs/api.rst
Expand Up @@ -459,10 +459,25 @@ this decorator if you are in a subclass of :class:`Client`.
.. warning::

This event is automatically handled by the client which automatically always accepts the user. If you have this event referenced in your code the client won't automatically handle it anymore and you must handle it youself.

.. note::

This event differs from :func:`event_party_join_request` by the fact that this event is fired whenever someone is in the middle of joining the party, while :func:`event_party_join_request` is called when someone explicitly requests to join your private party.

:param confirmation: Confirmation object with accessible confirmation methods.
:type confirmation: :class:`PartyJoinConfirmation`

.. function:: event_party_join_request(request)

This event is called when a friend requests to join your private party.

.. note::

This event differs from :func:`event_party_member_confirm` by the fact that this event is called when someone explicitly requests to join the bots party, while :func:`event_party_member_confirm` is an event that is fired whenever someone is in the middle of joining the party.

:param request: Request object.
:type request: :class:`PartyJoinRequest`

.. function:: event_party_member_chatban(member, reason)

This event is called whenever a member of the party has been banned from the party chat.
Expand Down Expand Up @@ -513,18 +528,18 @@ this decorator if you are in a subclass of :class:`Client`.
:param after: The current party privacy.
:type after: :class:`Privacy`

.. function:: event_party_team_swap(member, other)
.. function:: event_party_member_team_swap(member, other)

.. note::

Because of how party teams work, you can swap team with another member without their permission. If you don't want this to be possible, you can set ``team_change_allowed`` to ``False`` in :class:`DefaultPartyConfig`.

This event is called whenever a party member swaps party team with another member. You can get their new positions from :attr:`PartyMember.position`.
This event is called whenever a party member swaps their position. If the member switches to a position that was taken my another member, the two members will swap positions. You can get their new positions from :attr:`PartyMember.position`.

:param member: The member that instigated the team swap.
:type member: :class:`PartyMember`
:param other: The member that was swapped teams with.
:type other: :class:`PartyMember`
:param other: The member that was swapped teams with. If no member was previously holding the position, this will be ``None``.
:type other: Optional[:class:`PartyMember`]

.. function:: event_party_member_ready_change(member, before, after)

Expand Down Expand Up @@ -1026,6 +1041,14 @@ PartyJoinConfirmation
.. autoclass:: PartyJoinConfirmation()
:members:

PartyJoinRequest
~~~~~~~~~~~~~~~~

.. attributetable:: PartyJoinRequest

.. autoclass:: PartyJoinRequest
:members:

Presence
~~~~~~~~

Expand Down Expand Up @@ -1152,6 +1175,14 @@ Avatar
.. autoclass:: Avatar()
:members:

SquadAssignment
~~~~~~~~~~~~~~~

.. attributetable:: SquadAssignment

.. autoclass:: SquadAssignment()
:members:


Exceptions
----------
Expand All @@ -1170,6 +1201,8 @@ Exceptions

.. autoexception:: PartyError

.. autoexception:: PartyIsFull

.. autoexception:: Forbidden

.. autoexception:: NotFound
Expand All @@ -1183,3 +1216,7 @@ Exceptions
.. autoexception:: InviteeMaxFriendshipsExceeded

.. autoexception:: InviteeMaxFriendshipRequestsExceeded

.. autoexception:: FriendOffline

.. autoexception:: InvalidOffer
43 changes: 43 additions & 0 deletions docs/changelog.rst
Expand Up @@ -6,6 +6,49 @@ Changelog
Detailed version changes.


v3.6.0
------

Changes
~~~~~~~

- (**Breaking**) Party member meta change events like :func:`event_party_member_outfit_change()` are no longer emitted by the initial meta update that is received when a member joins the party.
- (**Breaking**) The "other" argument in :func:`event_party_member_team_swap()` can now be ``None`` if the member swapped to an empty position.

Added
~~~~~

- (**Breaking**) Added :exc:`PartyIsFull` exception which is now raised by :class:`Client.join_party()`.
- Added functionality related to the new "Request to join" feature.
- Added :meth:`Friend.request_to_join()`. Read the warning field in the docs before using it.
- Added :func:`event_party_join_request()`.
- Completely reworked party squad assignments and added functionality related to it.
- Added the following kwargs to :class:`DefaultPartyConfig`:
- ``default_squad_assignment``
- ``position_priorities``
- ``reassign_positions_on_size_change``
- Added :meth:`ClientPartyMember.set_position()`.
- Added :meth:`ClientParty.set_squad_assignments()`. This can be used to "hide" certain members and also change their positions.
- Added :attr:`ClientParty.squad_assignments`.
- Added :attr:`PartyMember.hidden`.
- Added kwarg ``wait_for_member_meta_in_events`` to :class:`Client`. It is ``True`` by default which introduces a ~1 sec delay to :func:`event_party_member_join()`.
- Added :meth:`Friend.owns_offer()` which can be used to check if a friend owns an offer currently in the item-shop.
- Added timestamps for season 16.

Bug Fixes
~~~~~~~~~

- Fixed an issue that caused the client to think that it was party leader after promoting someone else.
- Fixed a rare race condition that could cause :func:`event_party_member_promote()` to pass the new leaders object as the old one.
- Fixed some applications not closing smoothly due to another bug fix.
- Fixed a relatively hidden bug in :meth:`PartyMember.swap_position()`.

Misc
~~~~

- Fixed :func:`event_party_member_team_swap()` having the incorrect name specified in the docs.


v3.5.0
------

Expand Down
4 changes: 2 additions & 2 deletions fortnitepy/__init__.py
Expand Up @@ -25,7 +25,7 @@
SOFTWARE.
"""

__version__ = '3.5.0'
__version__ = '3.6.0'

from .client import Client, run_multiple, start_multiple, close_multiple
from .auth import (Auth, EmailAndPasswordAuth, ExchangeCodeAuth,
Expand All @@ -36,7 +36,7 @@
from .party import (DefaultPartyConfig, DefaultPartyMemberConfig, PartyMember,
ClientPartyMember, JustChattingClientPartyMember, Party,
ClientParty, ReceivedPartyInvitation, SentPartyInvitation,
PartyJoinConfirmation)
PartyJoinConfirmation, PartyJoinRequest, SquadAssignment)
from .presence import Presence, PresenceGameplayStats, PresenceParty
from .user import (ClientUser, User, BlockedUser, ExternalAuth,
UserSearchEntry, SacSearchEntryUser)
Expand Down
19 changes: 17 additions & 2 deletions fortnitepy/client.py
Expand Up @@ -37,7 +37,7 @@
from .errors import (PartyError, HTTPException, NotFound, Forbidden,
DuplicateFriendship, FriendshipRequestAlreadySent,
MaxFriendshipsExceeded, InviteeMaxFriendshipsExceeded,
InviteeMaxFriendshipRequestsExceeded)
InviteeMaxFriendshipRequestsExceeded, PartyIsFull)
from .xmpp import XMPPClient
from .http import HTTPClient
from .user import (ClientUser, User, BlockedUser, SacSearchEntryUser,
Expand Down Expand Up @@ -450,6 +450,7 @@ async def runner():
except KeyboardInterrupt:

if not _stopped:
_stopped = True
loop.run_until_complete(close_multiple(clients))
finally:
future.remove_done_callback(close)
Expand Down Expand Up @@ -535,6 +536,11 @@ class Client:
or simply is ``None`` on objects deriving from :class:`User`. Keep in
mind that :attr:`User.id` always will be available. You can use
:meth:`User.fetch()` to update all missing attributes.
wait_for_member_meta_in_events: :class:`bool`
Whether or not the client should wait for party member meta (information
about outfit, backpack etc.) before dispatching events like
:func:`event_party_member_join()`. If this is disabled then member objects
in the events won't have the correct meta. Defaults to ``True``.
Attributes
----------
Expand Down Expand Up @@ -568,6 +574,7 @@ def __init__(self, auth, *,
self.service_port = kwargs.get('xmpp_port', 5222)
self.cache_users = kwargs.get('cache_users', True)
self.fetch_user_data_in_events = kwargs.get('fetch_user_data_in_events', True) # noqa
self.wait_for_member_meta_in_events = kwargs.get('wait_for_member_meta_in_events', True) # noqa

self.kill_other_sessions = True
self.accept_eula = True
Expand Down Expand Up @@ -2966,7 +2973,7 @@ async def _create_party(self,
**default_schema,
**updated,
**edit_updated,
**party.construct_squad_assignments(),
**party._construct_raw_squad_assignments(),
**party.meta.set_voicechat_implementation('EOSVoiceChat')
},
deleted=[*deleted, *edit_deleted],
Expand Down Expand Up @@ -3091,6 +3098,8 @@ async def join_party(self, party_id: str) -> ClientParty:
You are already a member of this party.
NotFound
The party was not found.
PartyIsFull
The party you attempted to join is full.
Forbidden
You are not allowed to join this party because it's private
and you have not been a part of it before.
Expand Down Expand Up @@ -3129,6 +3138,12 @@ async def join_party(self, party_id: str) -> ClientParty:
'You are not allowed to join this party.'
)

m = 'errors.com.epicgames.social.party.party_is_full'
if e.message_code == m:
raise PartyIsFull(
'The party you attempted to join is full.'
)

raise

try:
Expand Down
5 changes: 4 additions & 1 deletion fortnitepy/enums.py
Expand Up @@ -215,6 +215,7 @@ class SeasonStartTimestamp(Enum):
SEASON_13 = 1592352001
SEASON_14 = 1598486401
SEASON_15 = 1606867201
SEASON_16 = 1615852801


class SeasonEndTimestamp(Enum):
Expand All @@ -232,14 +233,16 @@ class SeasonEndTimestamp(Enum):
SEASON_12 = 1592352000
SEASON_13 = 1598486400
SEASON_14 = 1606867200
SEASON_15 = 1615852800


class BattlePassStat(Enum):
SEASON_11 = ('s11_social_bp_level', SeasonEndTimestamp.SEASON_11.value)
SEASON_12 = ('s11_social_bp_level', SeasonEndTimestamp.SEASON_12.value)
SEASON_13 = (('s13_social_bp_level', 's11_social_bp_level'), SeasonEndTimestamp.SEASON_13.value)
SEASON_14 = ('s14_social_bp_level', SeasonEndTimestamp.SEASON_14.value)
SEASON_15 = ('s15_social_bp_level', None)
SEASON_15 = ('s15_social_bp_level', SeasonEndTimestamp.SEASON_15.value)
SEASON_16 = ('s16_social_bp_level', None)


class KairosBackgroundColorPreset(Enum):
Expand Down
22 changes: 21 additions & 1 deletion fortnitepy/errors.py
Expand Up @@ -25,7 +25,10 @@
"""

from aiohttp import ClientResponse
from typing import Union
from typing import Union, TYPE_CHECKING

if TYPE_CHECKING:
from .http import Route # noqa


class FortniteException(Exception):
Expand Down Expand Up @@ -69,6 +72,10 @@ class PartyError(FortniteException):
pass


class PartyIsFull(FortniteException):
"""This exception is raised when the bot attempts to join a full party."""


class Forbidden(FortniteException):
"""This exception is raised whenever you attempted a request that your
account does not have permission to do.
Expand Down Expand Up @@ -126,6 +133,19 @@ class InviteeMaxFriendshipRequestsExceeded(FortniteException):
pass


class FriendOffline(FortniteException):
"""This exception is raised when an action that requires a friend to be
online is performed at an offline friend.
"""
pass


class InvalidOffer(FortniteException):
"""This exception is raised when an invalid/outdated offer is
passed. Only offers currently in the item shop are valid."""
pass


class ValidationFailure(FortniteException):
"""Represents a validation failure returned.
Expand Down
82 changes: 79 additions & 3 deletions fortnitepy/friend.py
Expand Up @@ -27,10 +27,10 @@
import datetime

from typing import TYPE_CHECKING, List, Optional
from aioxmpp import JID

from .user import UserBase, ExternalAuth
from .errors import PartyError, Forbidden, HTTPException
from .user import UserBase
from .errors import (FriendOffline, InvalidOffer, PartyError, Forbidden,
HTTPException)
from .presence import Presence
from .enums import Platform

Expand Down Expand Up @@ -457,6 +457,82 @@ async def invite(self) -> None:
"""
return await self.client.party.invite(self.id)

async def request_to_join(self) -> None:
"""|coro|
Sends a request to join a friends party. This is mainly used for
requesting to join private parties specifically, but it can be used
for all types of party privacies.
.. warning::
If the request is accepted by the receiving friend, the bot will
receive a regular party invitation. Unlike the fortnite client,
fortnitepy will not automatically accept this invitation. You have
to make some logic for doing that yourself.
Raises
------
PartyError
You are already a part of this friends party.
FriendOffline
The friend you requested to join is offline.
HTTPException
An error occured while requesting.
"""
try:
await self.client.http.party_send_intention(self.id)
except HTTPException as exc:
m = 'errors.com.epicgames.social.party.user_already_in_party'
if exc.message_code == m:
raise PartyError(
'The bot is already a part of this friends party.'
)

m = 'errors.com.epicgames.social.party.user_has_no_party'
if exc.message_code == m:
raise FriendOffline(
'The friend you requested to join is offline.'
)

raise

async def owns_offer(self, offer_id: str) -> bool:
"""|coro|
Checks if a friend owns a currently active offer in the item shop.
Raises
------
InvalidOffer
An invalid/outdated offer_id was passed. Only offers currently in
the item shop are valid.
HTTPException
An error occured while requesting.
Returns
-------
:class:`bool`
Whether or not the friend owns the offer.
"""
try:
await self.client.http.fortnite_check_gift_eligibility(
self.id,
offer_id,
)
except HTTPException as exc:
m = 'errors.com.epicgames.modules.gamesubcatalog.purchase_not_allowed' # noqa
if exc.message_code == m:
return True

m = 'errors.com.epicgames.modules.gamesubcatalog.catalog_out_of_date' # noqa
if exc.message_code == m:
raise InvalidOffer('The offer_id passed is not valid.')

raise

return False


class PendingFriendBase(FriendBase):
"""Represents a pending friend from Fortnite."""
Expand Down

0 comments on commit 09f7828

Please sign in to comment.