Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DotaPlus Endpoints Request #2100

Open
Tsury opened this issue Mar 9, 2020 · 6 comments
Open

DotaPlus Endpoints Request #2100

Tsury opened this issue Mar 9, 2020 · 6 comments

Comments

@Tsury
Copy link

Tsury commented Mar 9, 2020

Hey @howardchung, following our talk on Discord, here are the required API calls for DotaPlus - Just 2 endpoints.
I tried to make them as minimal as possible and used the same field names and conventions of the existing OpenDota API whenever I could.

GET /dotanext/matchPlayers
For each supplied account_id, return some general account info and some match info for each of their matches within the supplied game_mode, lobby_type and date parameters. If also supplied enemy_account_id or ally_account_id, return the lifetime wins and loses against or with supplied account ID, respectively.

Query Parameters:

  • game_mode: Same for the rest of the API
  • lobby_type: Same for the rest of the API
  • date: Same for the rest of the API
  • account_id: Array of Steam IDs of players for which to get info
  • enemy_account_id: Optional. Cannot appear when ally_account_id is supplied. A Steam ID to get lifetime wins/loses against (as enemy), for all supplied account_ids (win/lose)
  • ally_account_id: Optional. Cannot appear when enemy_account_id is supplied. A Steam ID to get lifetime wins/loses with (as ally), for all supplied account_ids (win/lose)

Response:
The response will be an object, with a key for each supplied account_id, and a value that looks like this:

  • win (integer): Lifetime wins (same as /player/wl)
  • lose (integer): Lifetime losses (same as /player/wl)
  • personaname (string): Account name
  • name (string): Pro player name if applicable, or null
  • rank_tier (integer): Rank tier of the player
  • leaderboard_rank (integer): Leaderboard rank of player
  • previous_season_rank_tier (integer): (NEW FIELD) The final rank tier of the player from last season, before this seasons' recalibration time.
  • previous_season_leaderboard_rank (integer): (NEW FIELD) The final leaderboard rank of the player from last season, before this seasons' recalibration time.
  • enemy (object): If supplied enemy_account_id, an object containing win (integer) and lose (integer), of the lifetime wins and loses of the player against enemy_account_id, otherwise (or if no results) null/undefined.
  • ally (object): If supplied ally_account_id, an object containing win (integer) and lose (integer), of the lifetime wins and loses of the player with ally_account_id, otherwise (or if no results) null/undefined.
  • matches (array of objects): Array containing and object for each match returned.
    • match_id (integer): Id of the match
    • account_id (integer): Id of the player
    • radiant_win (boolean): true if Radiant won
    • rank_tier (integer): (NEW FIELD) The average rank tier of the match which is basically the average rank of all 10 players (it's a little trickier than just a simple average of course). If you don't want to calculate it yourself, you can just call it 'rank_tiers' and return an integer array which will contain the rank tiers of all 10 players instead.
    • start_time (integer): Timestamp of start of the match
    • duration (integer): Match duration
    • game_mode (integer): Game mode
    • lobby_type (integer) Lobby type
    • player (object): An object containing some info about the player in that match. It contains only fields already known to you from the general /matches/ endpoint, so I will just list them:
      • player_slot
      • hero_id
      • kills
      • deaths
      • assists
      • leaver_status
      • gold_per_min
      • xp_per_min
      • randomed
      • lane
      • lane_role
      • purchase_ward_observer
      • purchase_ward_sentry
      • last_hits
      • total_gold

Notes:

  • Regarding the 3 new fields, if it's not possible, I will manage without them.
  • Performance-wise, if you see something that can cause an issue, please tell me. If the ally/enemy part requires too much processing, I'll remove it.
  • Date will probably never be more than 90 days. The app currently has presets of 7, 30, 90 days, 30 is the default,
  • This endpoint will be called twice for each game, once for the enemy team (5 ids) with the local player as enemy_account_id, and then for the local player's team (5 ids), with the local player as ally_account_id. The first call needs to finish between the loading/connection phase and the beginning of the ban phase, that's why performance is important.
  • For spectated games this endpoint will be called once, with 10 ids and no ally/enemy info.

Example URL:
https://api.opendota.com/api/dotanext/matchPlayers/?account_id=94531730&account_id=351659733&account_id=104963314&account_id=345803031&account_id=206144913&enemy_account_id=81256461&game_mode=2,3,22&lobby_type=0,1,7,9&date=30

Example response (not for the supplied URL): It's just a basic response with 2 players and for each of them 2 matches (copy-pasted). Just to see the structure.


GET /dotanext/playerHeroPurchaseLogs
For the supplied account_id and hero_id, return his purchase_log for each of the matches within the supplied hero_id, game_mode, lobby_type and date parameters.

Query Parameters:

  • account_id: An account ID for which to get purchase_logs.
  • hero_id: A hero ID for which to get purchase_logs.

Path Parameters:

  • game_mode: Same for the rest of the API
  • lobby_type: Same for the rest of the API
  • date: Same for the rest of the API

Response:
An array of purchase logs. Account/match IDs are not needed. Purely an array of purchase logs for each match.

Example URL:
https://api.opendota.com/api/dotanext/playerHeroPurchaseLogs/94531730/68?game_mode=2,3,22&lobby_type=0,1,7,9&date=30

Example response: Simply an array of purchase logs


That's about it. I hope it's not too much and that it's possible. Thank you for your time and effort.
Feel free to DM me on Discord if you have any questions, or just ask here.

@howardchung
Copy link
Member

So for /matchPlayers, this appears to be data that could be assembled with the existing APis. Is the number of calls too high to do this by making individual calls?

Similarly for purchase logs, this data could be fetched by making individual calls to the match IDs you find in the matches listing, but this could be very inefficient.

We don't currently index in the match listing the full purchase log, but we do track the "time of first purchase" of each item, which might be enough for you:
https://api.opendota.com/api/players/88367253/matches?project=purchase_time&limit=100

@Tsury
Copy link
Author

Tsury commented Mar 31, 2020

I can't know for sure until I try to map all of the data into existing API calls, but it looks like every match will require between 4 and 5 calls per player (3-4 exclusiding purchase log), so for 10 players that will be around 40-50 calls. Putting aside the high amount of calls, in cases where a player fails to connect into a match and you are thrown into a new match, it may even exceed the 60 calls per minute limit. The other issue is the time-criticality. I'm not sure it's possible to reliably fetch all required info for bans suggestions within time limits, when taking into account poor network conditions/geographical aspects.

I can try to build a rough tester and check the feasibility, but even if I am able to make something work, I will be worried about its performance and realiability.

If it makes it any less of a big deal, I can forfiet the purchase logs endpoint for now.

@howardchung
Copy link
Member

I believe we can't get around the 10 players part, since even if we aggregate the logic on the server side it'll still make the same queries to the database so the load isn't that much less. We could however combine the 4-5 possibly since it looks like your requested data is a combination of calls to /player, /player/matches and /player/wl, and we could assemble some of that data with one pass.

Purchase logs: If the example data I linked above won't fit your needs maybe we should skip that one for now. It'll use a lot more space to cache the full purchase logs in a way that can be queried by player.

@Tsury
Copy link
Author

Tsury commented Mar 31, 2020

Aggregating the logic on the server side may not improve the time it takes the server to handle 10 players, but it will definitely improve the overall time it takes to eventually get all of the info due to the (much) lower amount of network calls required. I know this from my experience with STARTZ's API.

But yeah, even if you don't aggregate the logic on the server, combining the required data into 1 call per player will probably make it feasible. We can maybe revisit the aggregation part afterwards.

Regarding the purchase logs, I missed what you originally said about what data you keep. From what I see, having the first time of purchase for each type of item will be enough for me.

@howardchung
Copy link
Member

Note that the purchase data is actually the sum of the purchase times, since I think I was trying to compute "average time of purchase" for each item. This may have unexpected results if a player buys multiples of the same item...

Sounds like a plan for the player data endpoint. Are you planning to implement the new endpoint yourself? I can probably do it, but might be a bit of a delay before I can get started

@Tsury
Copy link
Author

Tsury commented Mar 31, 2020

I need the purchase data mainly for "interesting" items (bkb, hex, scepter, pipe, etc), so usually these are bought only once (rip selling bkb days), so should be fine.

I can look at the code and see how comfortable I am with implementing it myself. Haven't seen any code yet :) If I do it myself, can I bundle in the server-side aggregation of players? I really want it...

In any case thank you for your time and help, appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants