League of Legends Assistant Part 1 - Architecture

Posted on : October 16, 2021 Reading Time: 10 mins

app image This is the first of several blogs, where I will explain my process when developing the League of Legends assistant app, there is a previous post in my portfolio, where I briefly comment on how it works and what it does.

App needs

As I mentioned in the post about the app, the main objective is to generate updated statistics for each character, so that without having to be reading the game patches, the player can make decisions about which characters to choose or block, as well as what equipment to carry.

Before designing the architecture, the first thing we need is to know what resources we have and where we are going to get the information. In this case, RiotGames provides us with an API, where you can obtain information about players and their games.

The api provides us with a couple of key endpoints that we must use to reach the final data, which is the final information of each champion used in a match.

Available Endpoints

  • /lol/league/v4/entries/{queue}/{tier}/{division}: Gives us a list of players in a league
  • /lol/match/v4/matchlists/by-account/: Gives us a list of a player’s matches
  • /lol/match/v4/matches/: Gives us the detail of a specific match

Based on these endpoints, the process to reach the match detail and obtain the data of each champion is as follows:

  1. We obtain a list of players from each league/division
  2. We obtain a list of matches by going through those players
  3. We go through those matches and get the detail of each one

API Limitations

The api limits us to a certain amount of requests per minute, however, this limit applies per server, that is, if we exceed the limit on the Korean server, we can continue making requests from the North American server. From this comes a strategy to optimize requests that I will detail later.

Plan and Architecture

Architecture The plan is to use the Celery library to keep processes running that go obtaining match data, and in turn updating both the list of players and the list of matches, discarding old ones and removing inactive players from the list that we are not going to obtain information from.

From this a series of processes arise that will run on the server to carry out these tasks, I will number some of the most important:

1 - Player Collection

Code block 1

Through Celery Beat, every other day a tour is made of each available server, league and division, storing all player information in PostgreSQL. From each of them the server they belong to, their league, division, name and various IDS that are later required to make other requests with the api are stored.

2 - Game Collection

Code block 2

Using Supervisor, a process is kept running for each server, each of them going through the list of players associated with that server, getting a list of recent matches.

For each player, the last date on which this process checked it is obtained, so that the next time their matches are requested, it is only done with matches after that date. This way, duplicates are avoided.

Once the matches of the players in a certain region are obtained, they are stored in a Redis list, where the key is the region of the match.

3 - Getting Match Details

Code block 3 Also using supervisor, a handful of matches are extracted from the Redis queue of matches to be processed from each server (this way we avoid to some extent the API request limit).

These matches go to a Celery worker queue where their detail is requested, the information of each player who participated in it and everything relevant to it is stored in PostgreSQL.

Some of the data obtained from each match are: Characters played and blocked, kills, deaths and assists of each character, items and runes of each character, number of minions killed by each player, line of each character, among others.

4 - Obtaining Statistics

Code block 4 Once a good number of matches have been obtained (I have managed with about 100,000), what is done is to use pandas to obtain statistics for each character. This process is executed through Celery Beat every 24 hours or when a patch change is detected in the game, to keep the statistics updated.

In 100,000 matches, with 10 players, there is a sampling of 1,000,000 total data if divided by character. In this way we can obtain the following data for each character:

  • Frequent lines in which it is played
  • Ratio of times it is chosen/blocked
  • Win/loss ratio
  • Items and runes with a higher success rate
  • Characters against which you win/lose more
  • In which minute of the match you win/lose more

Some of these statistics are relevant to contrast them according to the line being played, that is, the equipment of a character can be very different if it is being played as Support or Middle. In this way we can obtain several different builds for each character according to the assigned line.

These statistics have a considerably complex structure, and are stored in MongoDB. The analysis of the data is too extensive to comment on in detail in this post, but perhaps I will write about it later.

Final comments

At this point we have already obtained the statistics of each character in each line, so in the next post I will be writing about how I designed the frontend, what functionalities it has and what technologies I used.

Next post - App Frontend