Skip to content

Commit

Permalink
Introduce ext.deadlock
Browse files Browse the repository at this point in the history
  • Loading branch information
Aluerie committed Oct 5, 2024
1 parent d5ec093 commit dbabb1a
Show file tree
Hide file tree
Showing 10 changed files with 567 additions and 0 deletions.
3 changes: 3 additions & 0 deletions steam/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,7 @@ def value(self) -> int:
DOTA2 = "DOTA 2", 570
CSGO = "Counter Strike Global-Offensive", 730
STEAM = "Steam", 753
DEADLOCK = "Deadlock", 1422450

@property
def _state(self) -> ConnectionState:
Expand All @@ -1442,6 +1443,8 @@ def _state(self) -> ConnectionState:
"""The Counter Strike Global-Offensive app."""
LFD2 = Apps.LFD2
"""The Left 4 Dead 2 app."""
DEADLOCK = Apps.DEADLOCK
"""The Deadlock app."""
STEAM = Apps.STEAM
"""The Steam app with context ID 6 (gifts)."""

Expand Down
12 changes: 12 additions & 0 deletions steam/ext/deadlock/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
steam.ext.deadlock
~~~~~~~~~~~~~~
A library for interacting with the Deadlock Game Coordinator.
Licensed under The MIT License (MIT) - Copyright (c) 2020-present James H-B. See LICENSE
"""

from .client import *
from .enums import *
from .models import *
59 changes: 59 additions & 0 deletions steam/ext/deadlock/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Licensed under The MIT License (MIT) - Copyright (c) 2020-present James H-B. See LICENSE"""

from __future__ import annotations

from typing import TYPE_CHECKING, Final

from ..._const import DOCS_BUILDING
from ..._gc import Client as Client_
from ...app import DEADLOCK
from ...ext import commands
from .models import ClientUser, PartialUser
from .state import GCState # noqa: TCH001

if TYPE_CHECKING:
from ...types.id import Intable
from ...utils import cached_property
from .models import User


__all__ = (
"Client",
"Bot",
)


class Client(Client_):
"""Represents a client connection that connects to Steam. This class is used to interact with the Steam API, CMs
and the Deadlock Game Coordinator.
:class:`Client` is a subclass of :class:`steam.Client`, so whatever you can do with :class:`steam.Client` you can
do with :class:`Client`.
"""

_APP: Final = DEADLOCK
_ClientUserCls = ClientUser
_state: GCState # type: ignore # PEP 705

if TYPE_CHECKING:

@cached_property
def user(self) -> ClientUser: ...

if TYPE_CHECKING or DOCS_BUILDING:

def get_user(self, id: Intable) -> User | None: ...

async def fetch_user(self, id: Intable) -> User: ...

# TODO: maybe this should exist as a part of the whole lib (?)
def instantiate_partial_user(self, id: Intable) -> PartialUser:
return self._state.get_partial_user(id)


class Bot(commands.Bot, Client):
"""Represents a Steam bot.
:class:`Bot` is a subclass of :class:`~steam.ext.commands.Bot`, so whatever you can do with
:class:`~steam.ext.commands.Bot` you can do with :class:`Bot`.
"""
127 changes: 127 additions & 0 deletions steam/ext/deadlock/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""Licensed under The MIT License (MIT) - Copyright (c) 2020-present James H-B. See LICENSE"""

from __future__ import annotations

from ...enums import IntEnum


class EMsg(IntEnum):
# EGCBaseClientMsg from source: gcsystemmsgs.proto

GCPingRequest = 3001
GCPingResponse = 3002
GCToClientPollConvarRequest = 3003
GCToClientPollConvarResponse = 3004
GCCompressedMsgToClient = 3005
GCCompressedMsgToClient_Legacy = 523
GCToClientRequestDropped = 3006
GCClientWelcome = 4004
GCServerWelcome = 4005
GCClientHello = 4006
GCServerHello = 4007
GCClientConnectionStatus = 4009
GCServerConnectionStatus = 4010

# EGCCitadelClientMessages from source: citadel_gcmessages_client.proto
ClientToGCStartMatchmaking = 9010
ClientToGCStartMatchmakingResponse = 9011
ClientToGCStopMatchmaking = 9012
ClientToGCStopMatchmakingResponse = 9013
GCToClientMatchmakingStopped = 9014
ClientToGCLeaveLobby = 9015
ClientToGCLeaveLobbyResponse = 9016
ClientToGCIsInMatchmaking = 9017
ClientToGCIsInMatchmakingResponse = 9018
GCToClientDevPlaytestStatus = 9019
ClientToGCDevSetMMBias = 9023
ClientToGCGetProfileCard = 9024
ClientToGCGetProfileCardResponse = 9025
ClientToGCUpdateRoster = 9026
ClientToGCUpdateRosterResponse = 9027
GCToClientProfileCardUpdated = 9028
GCToClientDevAnnouncements = 9029
ClientToGCModifyDevAnnouncements = 9030
ClientToGCModifyDevAnnouncementsResponse = 9031
GCToClientSDRTicket = 9100
ClientToGCReplacementSDRTicket = 9101
ClientToGCReplacementSDRTicketResponse = 9102
ClientToGCSetServerConVar = 9107
ClientToGCSetServerConVarResponse = 9108
ClientToGCSpectateLobby = 9109
ClientToGCSpectateLobbyResponse = 9110
ClientToGCPostMatchSurveyResponse = 9111
ClientToGCGetMatchHistory = 9112
ClientToGCGetMatchHistoryResponse = 9113
ClientToGCSpectateUser = 9116
ClientToGCSpectateUserResponse = 9117
ClientToGCPartyCreate = 9123
ClientToGCPartyCreateResponse = 9124
ClientToGCPartyLeave = 9125
ClientToGCPartyLeaveResponse = 9126
ClientToGCPartyJoin = 9127
ClientToGCPartyJoinResponse = 9128
ClientToGCPartyAction = 9129
ClientToGCPartyActionResponse = 9130
ClientToGCPartyStartMatch = 9131
ClientToGCPartyStartMatchResponse = 9132
ClientToGCPartyInviteUser = 9133
ClientToGCPartyInviteUserResponse = 9134
GCToClientPartyEvent = 9135
GCToClientCanRejoinParty = 9137
ClientToGCPartyJoinViaCode = 9138
ClientToGCPartyJoinViaCodeResponse = 9139
ClientToGCPartyUpdateRoster = 9140
ClientToGCPartyUpdateRosterResponse = 9141
ClientToGCPartySetReadyState = 9142
ClientToGCPartySetReadyStateResponse = 9143
ClientToGCGetAccountStats = 9164
ClientToGCGetAccountStatsResponse = 9165
GCToClientAccountStatsUpdated = 9166
ClientToGCGetMatchMetaData = 9167
ClientToGCGetMatchMetaDataResponse = 9168
ClientToGCDevAction = 9172
ClientToGCDevActionResponse = 9173
ClientToGCRecordClientEvents = 9174
ClientToGCRecordClientEventsResponse = 9175
ClientToGCSetNewPlayerProgress = 9176
ClientToGCSetNewPlayerProgressResponse = 9177
ClientToGCUpdateAccountSync = 9178
ClientToGCUpdateAccountSyncResponse = 9179
ClientToGCGetHeroChoice = 9180
ClientToGCGetHeroChoiceResponse = 9181
ClientToGCUnlockHero = 9182
ClientToGCUnlockHeroResponse = 9183
ClientToGCBookUnlock = 9184
ClientToGCBookUnlockResponse = 9185
ClientToGCGetBook = 9186
ClientToGCGetBookResponse = 9187
GCToClientBookUpdated = 9188
ClientToGCSubmitPlaytestUser = 9189
ClientToGCSubmitPlaytestUserResponse = 9190
ClientToGCUpdateHeroBuild = 9193
ClientToGCUpdateHeroBuildResponse = 9194
ClientToGCFindHeroBuilds = 9195
ClientToGCFindHeroBuildsResponse = 9196
ClientToGCReportPlayerFromMatch = 9197
ClientToGCReportPlayerFromMatchResponse = 9198
ClientToGCGetAccountMatchReports = 9199
ClientToGCGetAccountMatchReportsResponse = 9200
ClientToGCDeleteHeroBuild = 9201
ClientToGCDeleteHeroBuildResponse = 9202
ClientToGCGetActiveMatches = 9203
ClientToGCGetActiveMatchesResponse = 9204
ClientToGCGetDiscordLink = 9205
ClientToGCGetDiscordLinkResponse = 9206
ClientToGCPartySetMode = 9207
ClientToGCPartySetModeResponse = 9208
ClientToGCGrantForumAccess = 9209
ClientToGCGrantForumAccessResponse = 9210
ClientToGCModeratorRequest = 9211
ClientToGCModeratorRequestResponse = 9212
ClientToGCGetFriendGameStatus = 9213
ClientToGCGetFriendGameStatusResponse = 9214
ClientToGCUpdateHeroBuildPreference = 9215
ClientToGCUpdateHeroBuildPreferenceResponse = 9216
ClientToGCGetOldHeroBuildData = 9217
ClientToGCGetOldHeroBuildDataResponse = 9218
ClientToGCUpdateSpectatorStatus = 9219
55 changes: 55 additions & 0 deletions steam/ext/deadlock/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Licensed under The MIT License (MIT) - Copyright (c) 2020-present James H-B. See LICENSE"""

from __future__ import annotations

from typing import TYPE_CHECKING, TypeVar

from ... import abc, user
from ..._gc.client import ClientUser as ClientUser_

if TYPE_CHECKING:
from .protobufs import client_messages, common
from .state import GCState

UserT = TypeVar("UserT", bound=abc.PartialUser)

__all__ = (
"ClientUser",
"PartialUser",
"User",
)


class PartialUser(abc.PartialUser):
__slots__ = ()
_state: GCState

async def account_stats(self):
"""Fetch user's Deadlock account stats."""
proto = await self._state.fetch_account_stats(self.id, False, True)
return AccountStats(proto)


class User(PartialUser, user.User): # type: ignore
__slots__ = ()


class ClientUser(PartialUser, ClientUser_): # type: ignore
# TODO: if TYPE_CHECKING: for inventory
...


class AccountStats:
def __init__(self, proto: client_messages.ClientToGCGetAccountStatsResponse):
self.account_id = proto.stats.account_id
self.stats = [AccountHeroStats(p) for p in proto.stats.stats]


class AccountHeroStats:
def __init__(self, proto: common.AccountHeroStats) -> None:
self.hero_id: int = proto.hero_id # TODO: Modelize Enum
self.stat_id: list[int] = proto.stat_id
self.total_value: list[int] = proto.total_value
self.medals_bronze: list[int] = proto.medals_bronze
self.medals_silver: list[int] = proto.medals_silver
self.medals_gold: list[int] = proto.medals_gold
14 changes: 14 additions & 0 deletions steam/ext/deadlock/protobufs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import Final

import betterproto

APP_ID: Final = 1422450

from ....protobufs.msg import GCProtobufMessage
from . import (
client_messages as client_messages,
common as common,
sdk as sdk,
)

[setattr(cls, "_betterproto", betterproto.ProtoClassMetadata(cls)) for cls in GCProtobufMessage.__subclasses__()]
31 changes: 31 additions & 0 deletions steam/ext/deadlock/protobufs/client_messages.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions steam/ext/deadlock/protobufs/common.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit dbabb1a

Please sign in to comment.