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

v2.0.0b2 #344

Merged
merged 9 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.9", "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11"] # Add 3.12 when pxr updates
timeout-minutes: 15
steps:
- name: Checkout awpy library
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:

- name: Install Poetry
uses: abatilo/actions-poetry@v2

- name: Setup a local virtual environment for poetry
shell: bash
run: |
Expand Down
68 changes: 60 additions & 8 deletions awpy/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,79 @@
from typing import Literal, Optional

import click
import requests
from loguru import logger
from tqdm import tqdm

from awpy import Demo
from awpy.data import AWPY_DATA_DIR
from awpy.data.usd_data import USD_LINKS


@click.group()
def awpy() -> None:
"""A simple CLI interface for Awpy."""


@awpy.command(help="Get Counter-Strike 2 resources like map files.")
@click.argument("resource_type", type=click.Choice(["map", "usd"]))
@click.argument("resource_name", type=str)
def get(resource_type: Literal["usd"], resource_name: str) -> None:
@awpy.command(
help="Get Counter-Strike 2 resources like map images, nav meshes or usd files."
)
@click.argument("resource_type", type=click.Choice(["map", "nav", "usd"]))
@click.argument("resource_name", required=False)
def get(
resource_type: Literal["map", "nav", "usd"], resource_name: Optional[str]
) -> None:
"""Get a resource given its type and name."""
if not AWPY_DATA_DIR.exists():
AWPY_DATA_DIR.mkdir(parents=True, exist_ok=True)
awpy_data_dir_creation_msg = f"Created awpy data directory at {AWPY_DATA_DIR}"
logger.debug(awpy_data_dir_creation_msg)

if resource_type == "usd":
if resource_name == "all":
logger.info("Getting all USDs...")
if resource_name:
url = USD_LINKS.get(resource_name)
if not url:
logger.error(f"No USD link found for {resource_name}")
return
usd_data_dir = AWPY_DATA_DIR / "usd"
usd_data_dir.mkdir(parents=True, exist_ok=True)
usd_file_path = usd_data_dir / f"{resource_name}.usdc"
logger.info(f"Getting USD for {resource_name}...")
response = requests.get(url, stream=True, timeout=300)
total_size = int(response.headers.get("content-length", 0))
block_size = 1024
with (
tqdm(total=total_size, unit="B", unit_scale=True) as progress_bar,
open(usd_file_path, "wb") as file,
):
for data in response.iter_content(block_size):
progress_bar.update(len(data))
file.write(data)
logger.info(f"Saved USD for {resource_name} to {usd_file_path}")
else:
getting_specific_usd_msg = f"Getting USD for {resource_name}..."
logger.info(getting_specific_usd_msg)
logger.info("Getting all USDs...")
for map_name, url in USD_LINKS.items():
usd_data_dir = AWPY_DATA_DIR / "usd"
usd_data_dir.mkdir(parents=True, exist_ok=True)
usd_file_path = usd_data_dir / f"{map_name}.usdc"
logger.info(f"Getting USD for {map_name}...")
response = requests.get(url, stream=True, timeout=300)
total_size = int(response.headers.get("content-length", 0))
block_size = 1024
with (
tqdm(total=total_size, unit="B", unit_scale=True) as progress_bar,
open(usd_file_path, "wb") as file,
):
for data in response.iter_content(block_size):
progress_bar.update(len(data))
file.write(data)
logger.info(f"Saved USD for {map_name} to {usd_file_path}")
elif resource_type == "map":
map_not_impl_msg = "Map files are not yet implemented."
raise NotImplementedError(map_not_impl_msg)
elif resource_type == "nav":
nav_not_impl_msg = "Nav files are not yet implemented."
raise NotImplementedError(nav_not_impl_msg)


@awpy.command(help="Parse a Counter-Strike 2 demo file.")
Expand Down
4 changes: 4 additions & 0 deletions awpy/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
"""Module to hold Counter-Strike 2 data."""

from pathlib import Path

AWPY_DATA_DIR = Path.home() / ".awpy"
8 changes: 8 additions & 0 deletions awpy/data/usd_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""USD files for maps.

To make:
- Get Blender with SourceIO

"""

USD_LINKS = {"de_dust2": "https://figshare.com/ndownloader/files/47199475"}
17 changes: 13 additions & 4 deletions awpy/parsers/clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,29 @@ def parse_clock(
return f"{int(minutes):02}:{int(seconds):02}"


def _find_clock_time(row: pd.Series) -> str:
def _find_clock_time(row: pd.Series) -> Union[str, pd._libs.missing.NAType]:
"""Find the clock time for a row.

Args:
row: A row from a dataframe with ticks_since_* columns.

Returns:
str: The clock time in MM:SS format or NA if no valid time is found.
"""
times = {
"start": row["ticks_since_round_start"],
"freeze": row["ticks_since_freeze_time_end"],
"bomb": row["ticks_since_bomb_plant"],
}
# Filter out NA values and find the key with the minimum value
min_key = min((k for k in times if pd.notna(times[k])), key=lambda k: times[k])
return parse_clock(times[min_key], min_key)
# Filter out NA values
valid_times = {k: v for k, v in times.items() if pd.notna(v)}

if not valid_times:
return pd.NA

# Find the key with the minimum value among valid times
min_key = min(valid_times, key=valid_times.get)
return parse_clock(valid_times[min_key], min_key)


def parse_times(
Expand Down
2 changes: 1 addition & 1 deletion awpy/vis/__init__.py → awpy/plot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Awpy visualization module."""
"""Awpy plotting module."""

SIDE_COLORS = {"ct": "#5d79ae", "t": "#de9b35"}
SUPPORTED_MAPS = ["de_dust2"]
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions awpy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def apply_round_num(

# Add round
df["round"] = intervals.get_indexer(df[tick_col]) + 1
df["round"] = df["round"].replace(0, pd.NA)

return df

Expand Down
Loading