Show player and team stats of a currently played, replayed or last played Company of Heroes 2 match.
Example output on Windows Terminal with gruvbox colors and Inconsolata font.
You can either run CoH2 Live Stats as a standalone bundled application or install and run it with Python.
- Download latest release of CoH2LiveStats-bundle-[version].zip
- Unzip and run CoH2LiveStats.exe
- Run
pip install coh2-live-stats
- Run
python -m coh2_live_stats
or simplycoh2livestats
- Get source code
- Download and install Python >= 3.12
- Run
pip install .
from project root - Run
python -m coh2_live_stats
or simplycoh2livestats
- Microsoft Windows
- (Optional) Windows Terminal for proper UTF-8 support
- or Linux
CoH2 Live Stats is configured via a TOML configuration file. A default configuration file named _coh2livestats.toml
is supplied with the bundled application. A configuration file can be put in the user's home directory (%USERPROFILE%)
or left next to the application's executable.
A configuration file can have one of the following names:
- _coh2livestats.toml
- .coh2livestats.toml
- coh2livestats.toml
- _coh2_live_stats.toml
- .coh2_live_stats.toml
- coh2_live_stats.toml
The first valid configuration file detected in the above order is used. The following sections describe all available configuration attributes grouped by TOML table. All attributes ungrouped are found here. More information on TOML syntax is found here.
Attribute | Type | Description |
---|---|---|
logfile |
Path |
Path to observed Company of Heroes 2 log file (supports OS environment variables) |
Attribute | Type | Default | Description |
---|---|---|---|
play_sound |
bool |
true |
Play a notification sound when a new multiplayer match was found |
sound |
Path |
'horn' |
Built-in notification sound name or full path to custom waveform audio file |
Attribute | Type | Default | Description |
---|---|---|---|
color |
bool |
true |
Use color for output |
border |
Border |
'inner' |
Border type of the output table |
header |
bool |
true |
Show output table header |
show_average |
bool |
true |
Show team's average rank and level |
always_show_team |
bool |
false |
Always show team columns, even if they're empty |
drop_ratio_high_threshold |
float |
0.05 |
Drop ratios are considered high if they're higher than or equal this value (used for color) |
win_ratio_high_threshold |
float |
0.6 |
Win ratios are considered high if they're higher than or equal this value (used for color) |
win_ratio_low_threshold |
float |
0.5 |
Win ratios are considered low if they're lower than this value (used for color) |
prestige_star_char |
str |
'*' |
Character to use for one prestige level star |
prestige_half_star_char |
str |
'~' |
Character to use for a half prestige level star |
Attribute | Type | Default | Description |
---|---|---|---|
border |
Color |
'bright black' |
Output table border color |
label |
Color |
'bright black' |
Output table header color |
Attribute | Type | Default | Description |
---|---|---|---|
high_drop_rate |
Color |
'red' |
Color for a high player drop ratio |
high |
Color |
'bright white' |
Color for highest ranked player and high win ratio |
low |
Color |
'bright black' |
Color for lowest ranked player and low win ratio |
win_streak |
Color |
'green' |
Color for a win streak |
loss_streak |
Color |
'red' |
Color for a loss streak |
Attribute | Type | Default | Description |
---|---|---|---|
wm |
Color |
'red' |
Wehrmacht color |
su |
Color |
'red' |
Soviet Union color |
okw |
Color |
'cyan' |
Oberkommando West color |
us |
Color |
'blue' |
US Forces color |
uk |
Color |
'yellow' |
British Forces color |
Attribute | Description |
---|---|
faction |
Player faction |
rank |
Leaderboard rank if the player currently has a rank or highest known rank (indicator: +) if available or estimated rank (indicator: ?) |
level |
Rank level representing the leaderboard rank |
prestige |
Experience expressed in stars |
streak |
Number of games won (positive) or lost (negative) in a row |
wins |
Number of games won |
losses |
Number of games lost |
win_ratio |
Percentage of games won |
drop_ratio |
Percentage of games dropped |
num_games |
Total number of games played |
team |
The pre-made team the player is part of if any |
team_rank |
The current rank of the pre-made team if any |
team_level |
The current rank level of the pre-made team if any |
steam_profile |
Steam profile URL |
country |
Player country |
name |
Player name |
Attribute | Type | Description |
---|---|---|
label |
str |
column header |
visible |
bool |
Whether to show the column |
align |
Align |
column alignment |
pos |
int |
column position used for column ordering |
Type | Values |
---|---|
Border |
'full' , 'inner' or 'none' |
Align |
'l' , 'c' or 'r' |
Sound |
'horn_subtle' , 'horn' or 'horn_epic' |
Color |
'black' , 'red' , 'green' , 'yellow' , 'blue' , 'magenta' , 'cyan' , 'white' , 'bright black' , 'bright red' , 'bright green' , 'bright yellow' , 'bright blue' , 'bright magenta' , 'bright cyan' or 'bright white' |
- Add full border and remove the average row
- Remove column
drop_ratio
andnum_games
- Add column
streak
andprestige
- Move column
prestige
to the front - Move column
faction
in front of columnname
- Unify faction colors
[table]
border = 'full'
show_average = false
[table.columns.drop_ratio]
visible = false
[table.columns.num_games]
visible = false
[table.columns.streak]
visible = true
[table.columns.prestige]
visible = true
pos = -1
[table.columns.faction]
pos = 1
[table.columns.name]
pos = 2
[table.colors.faction]
okw = "red"
su = "blue"
uk = "blue"
A minimalistic output configuration
[table]
color = false
header = false
border = 'none'
show_average = false
[table.columns]
rank.visible = false
win_ratio.visible = false
drop_ratio.visible = false
num_games.visible = false
country.visible = false
team_rank.visible = false
-
Create virtual environment:
python -m venv venv
-
Activate virtual environment:
- Bash:
. venv/bin/activate
- PowerShell:
venv\Scripts\Activate.ps1
- cmd.exe:
venv\Scripts\activate.bat
- Bash:
-
Install project with development dependencies in editable mode:
$ pip install invoke
$ inv install --dev
- Install
pre-commit
hooks:
$ pre-commit install
- Install missing stub packages:
$ mypy --install-types --non-interactive src tests scripts tasks.py
- Build with
setuptools
andbuild
and create aPyInstaller
bundle:
$ inv build
- Distribution bundle:
.\dist_bundle\CoH2LiveStats-bundle-{version}.zip
- See
inv -l
andinv [task] -h
for more information on availableinvoke
tasks
All configuration options
Attribute | Type | Default | Description |
---|---|---|---|
logfile |
Path |
Path to observed Company of Heroes 2 log file (supports OS environment variables) | |
[notification] |
Notification sound settings | ||
notification.play_sound |
bool |
true |
Play a notification sound when a new multiplayer match was found |
notification.sound |
Path |
'horn' |
Built-in notification sound name or full path to custom waveform audio file |
[table] |
Output table settings | ||
table.color |
bool |
true |
Use color for output |
table.border |
Border |
'inner' |
Border type of the output table |
table.header |
bool |
true |
Show output table header |
table.show_average |
bool |
true |
Show team's average rank and level |
table.always_show_team |
bool |
false |
Always show team columns, even if they're empty |
table.drop_ratio_high_threshold |
float |
0.05 |
Drop ratios are considered high if they're higher than or equal this value (used for color) |
table.win_ratio_high_threshold |
float |
0.6 |
Win ratios are considered high if they're higher than or equal this value (used for color) |
table.win_ratio_low_threshold |
float |
0.5 |
Win ratios are considered low if they're lower than this value (used for color) |
table.prestige_star_char |
str |
'*' |
Character to use for one prestige level star |
table.prestige_half_star_char |
str |
'~' |
Character to use for a half prestige level star |
[table.colors] |
Output table color settings | ||
table.colors.border |
Color |
'bright black' |
Output table border color |
table.colors.label |
Color |
'bright black' |
Output table header color |
[table.colors.player] |
Player-specific color settings | ||
table.colors.player.high_drop_rate |
Color |
'red' |
Color for a high player drop ratio |
table.colors.player.high |
Color |
'bright white' |
Color for highest ranked player and high win ratio |
table.colors.player.low |
Color |
'bright black' |
Color for lowest ranked player and low win ratio |
table.colors.player.win_streak |
Color |
'green' |
Color for a win streak |
table.colors.player.loss_streak |
Color |
'red' |
Color for a loss streak |
[table.colors.faction] |
Faction colors | ||
table.colors.faction.wm |
Color |
'red' |
Wehrmacht color |
table.colors.faction.su |
Color |
'red' |
Soviet Union color |
table.colors.faction.okw |
Color |
'cyan' |
Oberkommando West color |
table.colors.faction.us |
Color |
'blue' |
US Forces color |
table.colors.faction.uk |
Color |
'yellow' |
British Forces color |
[table.columns] |
Output table columns | ||
[table.columns.faction] |
Player faction | ||
table.columns.faction.label |
str |
'Fac' |
faction header |
table.columns.faction.visible |
bool |
true |
Whether to show the faction |
table.columns.faction.align |
Align |
'l' |
faction alignment |
table.columns.faction.pos |
int |
0 |
faction position used for column ordering |
[table.columns.rank] |
Leaderboard rank if the player currently has a rank or highest known rank (indicator: +) if available or estimated rank (indicator: ?) | ||
table.columns.rank.label |
str |
'Rank' |
rank header |
table.columns.rank.visible |
bool |
true |
Whether to show the rank |
table.columns.rank.align |
Align |
'r' |
rank alignment |
table.columns.rank.pos |
int |
0 |
rank position used for column ordering |
[table.columns.level] |
Rank level representing the leaderboard rank | ||
table.columns.level.label |
str |
'Lvl' |
level header |
table.columns.level.visible |
bool |
true |
Whether to show the level |
table.columns.level.align |
Align |
'r' |
level alignment |
table.columns.level.pos |
int |
0 |
level position used for column ordering |
[table.columns.prestige] |
Experience expressed in stars | ||
table.columns.prestige.label |
str |
'XP' |
prestige header |
table.columns.prestige.visible |
bool |
false |
Whether to show the prestige |
table.columns.prestige.align |
Align |
'l' |
prestige alignment |
table.columns.prestige.pos |
int |
0 |
prestige position used for column ordering |
[table.columns.streak] |
Number of games won (positive) or lost (negative) in a row | ||
table.columns.streak.label |
str |
'+/-' |
streak header |
table.columns.streak.visible |
bool |
false |
Whether to show the streak |
table.columns.streak.align |
Align |
'l' |
streak alignment |
table.columns.streak.pos |
int |
0 |
streak position used for column ordering |
[table.columns.wins] |
Number of games won | ||
table.columns.wins.label |
str |
'W' |
wins header |
table.columns.wins.visible |
bool |
false |
Whether to show the wins |
table.columns.wins.align |
Align |
'l' |
wins alignment |
table.columns.wins.pos |
int |
0 |
wins position used for column ordering |
[table.columns.losses] |
Number of games lost | ||
table.columns.losses.label |
str |
'L' |
losses header |
table.columns.losses.visible |
bool |
false |
Whether to show the losses |
table.columns.losses.align |
Align |
'l' |
losses alignment |
table.columns.losses.pos |
int |
0 |
losses position used for column ordering |
[table.columns.win_ratio] |
Percentage of games won | ||
table.columns.win_ratio.label |
str |
'W%' |
win_ratio header |
table.columns.win_ratio.visible |
bool |
true |
Whether to show the win_ratio |
table.columns.win_ratio.align |
Align |
'r' |
win_ratio alignment |
table.columns.win_ratio.pos |
int |
0 |
win_ratio position used for column ordering |
[table.columns.drop_ratio] |
Percentage of games dropped | ||
table.columns.drop_ratio.label |
str |
'Drop%' |
drop_ratio header |
table.columns.drop_ratio.visible |
bool |
true |
Whether to show the drop_ratio |
table.columns.drop_ratio.align |
Align |
'r' |
drop_ratio alignment |
table.columns.drop_ratio.pos |
int |
0 |
drop_ratio position used for column ordering |
[table.columns.num_games] |
Total number of games played | ||
table.columns.num_games.label |
str |
'Total' |
num_games header |
table.columns.num_games.visible |
bool |
true |
Whether to show the num_games |
table.columns.num_games.align |
Align |
'l' |
num_games alignment |
table.columns.num_games.pos |
int |
0 |
num_games position used for column ordering |
[table.columns.team] |
The pre-made team the player is part of if any | ||
table.columns.team.label |
str |
'Team' |
team header |
table.columns.team.visible |
bool |
true |
Whether to show the team |
table.columns.team.align |
Align |
'c' |
team alignment |
table.columns.team.pos |
int |
0 |
team position used for column ordering |
[table.columns.team_rank] |
The current rank of the pre-made team if any | ||
table.columns.team_rank.label |
str |
'T_Rank' |
team_rank header |
table.columns.team_rank.visible |
bool |
true |
Whether to show the team_rank |
table.columns.team_rank.align |
Align |
'r' |
team_rank alignment |
table.columns.team_rank.pos |
int |
0 |
team_rank position used for column ordering |
[table.columns.team_level] |
The current rank level of the pre-made team if any | ||
table.columns.team_level.label |
str |
'T_Lvl' |
team_level header |
table.columns.team_level.visible |
bool |
true |
Whether to show the team_level |
table.columns.team_level.align |
Align |
'r' |
team_level alignment |
table.columns.team_level.pos |
int |
0 |
team_level position used for column ordering |
[table.columns.steam_profile] |
Steam profile URL | ||
table.columns.steam_profile.label |
str |
'Profile' |
steam_profile header |
table.columns.steam_profile.visible |
bool |
false |
Whether to show the steam_profile |
table.columns.steam_profile.align |
Align |
'l' |
steam_profile alignment |
table.columns.steam_profile.pos |
int |
0 |
steam_profile position used for column ordering |
[table.columns.country] |
Player country | ||
table.columns.country.label |
str |
'Country' |
country header |
table.columns.country.visible |
bool |
true |
Whether to show the country |
table.columns.country.align |
Align |
'l' |
country alignment |
table.columns.country.pos |
int |
0 |
country position used for column ordering |
[table.columns.name] |
Player name | ||
table.columns.name.label |
str |
'Name' |
name header |
table.columns.name.visible |
bool |
true |
Whether to show the name |
table.columns.name.align |
Align |
'l' |
name alignment |
table.columns.name.pos |
int |
0 |
name position used for column ordering |
Full default configuration
logfile = "%USERPROFILE%\\Documents\\My Games\\Company of Heroes 2\\warnings.log"
[notification]
play_sound = true
sound = "horn"
[table]
color = true
border = "inner"
header = true
show_average = true
always_show_team = false
drop_ratio_high_threshold = 0.05
win_ratio_high_threshold = 0.6
win_ratio_low_threshold = 0.5
prestige_star_char = "*"
prestige_half_star_char = "~"
[table.colors]
border = "BRIGHT_BLACK"
label = "BRIGHT_BLACK"
[table.colors.player]
high_drop_rate = "RED"
high = "BRIGHT_WHITE"
low = "BRIGHT_BLACK"
win_streak = "GREEN"
loss_streak = "RED"
[table.colors.faction]
wm = "RED"
su = "RED"
okw = "CYAN"
us = "BLUE"
uk = "YELLOW"
[table.columns]
[table.columns.faction]
label = "Fac"
visible = true
align = "l"
pos = 0
[table.columns.rank]
label = "Rank"
visible = true
align = "r"
pos = 0
[table.columns.level]
label = "Lvl"
visible = true
align = "r"
pos = 0
[table.columns.prestige]
label = "XP"
visible = false
align = "l"
pos = 0
[table.columns.streak]
label = "+/-"
visible = false
align = "l"
pos = 0
[table.columns.wins]
label = "W"
visible = false
align = "l"
pos = 0
[table.columns.losses]
label = "L"
visible = false
align = "l"
pos = 0
[table.columns.win_ratio]
label = "W%"
visible = true
align = "r"
pos = 0
[table.columns.drop_ratio]
label = "Drop%"
visible = true
align = "r"
pos = 0
[table.columns.num_games]
label = "Total"
visible = true
align = "l"
pos = 0
[table.columns.team]
label = "Team"
visible = true
align = "c"
pos = 0
[table.columns.team_rank]
label = "T_Rank"
visible = true
align = "r"
pos = 0
[table.columns.team_level]
label = "T_Lvl"
visible = true
align = "r"
pos = 0
[table.columns.steam_profile]
label = "Profile"
visible = false
align = "l"
pos = 0
[table.columns.country]
label = "Country"
visible = true
align = "l"
pos = 0
[table.columns.name]
label = "Name"
visible = true
align = "l"
pos = 0