Skip to content

Adding a New Statistic

Stephen Davis edited this page Feb 28, 2021 · 6 revisions

🎯 Overview

Statistics are what drives discord_ritoman They can be used to provide valuable insight into games and allow for different messages and actions to be taken by the bot. The system implemented to build statistics is plugin in nature and allows for statistics to be recomputed at any time, rely on other predefined statistics having been calculated and allows for individual statistics to define their own API. This document will outline how to build a statistic and utilize all of its features.

🗃️ Using Statistics

Before writing a new statistic its best to check if it has already been defined. The goal of this API is to reduce total computation needed to compute all statistics. All defined statistics can be accessed via the get_stat method. This method takes a single parameter stat_name which is the unique name of the statistic being queried. It will then either return a raw value (such as a string, int, or float) or might return a complex value such as a List or Dict. It is up to the individual API to define its return type.

# Example statistic usage

# this uses the winner stat API to get if the user being processed won
# the return type for this specific API is a dictionary where one of the
# key value pairs is "user": bool
did_user_win = get_stat('winner')['user']

Note: The statistics API currently has a limited usage which is currently scoped to just the rules API. This is because stats are designed to be used per user after a single game has been ended.

📁 File Structure

Creating a new statistic is designed to be modular and scalable as well as simplistic. To achieve these 3 goals, the statistic API requires that all statistics be defined in a special folder discord_ritoman/lol/stats/. The API will load all statistics defined in this folder at runtime so they can be provided to other parts of the application. Each new statistic should be defined in its own file discord_ritoman/lol/stats/<mystat>.py where mystat is the name of the statistic.

# visualization of file structure

# discord_ritoman
# |
# +-- lol
# |   |
# |   +-- stats
# |   |   +-- __init__.py
# |   |   +-- mystat.py

Note: when adding a new statistic this is the only file needed to fully implement it

✏️ Defining a New Statistic

For defining a new statistic there are 2 main components defined by the API for you usage lol_match_stat and LoLMatchStat. These look similar but the difference is LoLMatchStat is a generic class that you implement and lol_match_stat is a class decorator that is used to register that statistic with the API. Both of these are used together to define a statistic. This will become clearer with the following example.

# in discord_ritoman/lol/stats/mystat.py
from typing import Dict, Any
from discord_ritoman.lol.stats.match_stat import (
    lol_match_stat, # decorator
    LoLMatchStat   # base class
)


# this decorator registers this stat with the unique name
# "mystat" and the required stats "kills" and "deaths" to
# be processed before this one. This way as shown below
# those stats can be accessed to calculate this one
@lol_match_stat("mystat", requires=["kills", "deaths"])
class MyStat(LoLMatchStat):
    def process(self, data: Dict[str, Any], timeline: Dict[str, Any], account_id: str,) -> Any:
        """
        Function to process and calculate the statistic. The match data,
        timeline and current user's account ID are passed by default. 
        """

        # this doesn't fail because we specify that both "kills" and
        # "deaths" are calculated before this (see decorator above) 
        kills = get_stat("kills") 
        deaths = get_stat("deaths")
        
        # At the end of this function we return the final statistic
        return kills['total_kills'] / deaths['total_deaths']

This example statistic can then be accessed via

mystat_value = get_stat("mystat")

🧪 Testing

Clone this wiki locally