From 34c7db49696bcd63599ef5ceb1db56eb21223eb6 Mon Sep 17 00:00:00 2001 From: Jan-Eric Nitschke <47750513+JanEricNitschke@users.noreply.github.com> Date: Tue, 4 Mar 2025 19:45:23 +0100 Subject: [PATCH] Add option to also parse player clippings --- awpy/cli.py | 7 +++++-- awpy/visibility.py | 33 ++++++++++++++++++++++++++++----- scripts/generate-tris.ps1 | 13 +++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/awpy/cli.py b/awpy/cli.py index 18020b9d..a75c0149 100644 --- a/awpy/cli.py +++ b/awpy/cli.py @@ -115,9 +115,12 @@ def parse_mapdata(overview_dir: Path) -> None: @awpy_cli.command(name="tri", help="Parse triangles (*.tri) from a .vphys file.", hidden=True) @click.argument("vphys_file", type=click.Path(exists=True)) @click.option("--outpath", type=click.Path(), help="Path to save the parsed triangle.") -def generate_tri(vphys_file: Path, *, outpath: Path | None = None) -> None: +@click.option( + "--include_player_clippings", is_flag=True, default=False, help="Include player clippings in tri generation." +) +def generate_tri(vphys_file: Path, *, outpath: Path | None = None, include_player_clippings: bool) -> None: """Parse a .vphys file into a .tri file.""" vphys_file = Path(vphys_file) - vphys_parser = VphysParser(vphys_file) + vphys_parser = VphysParser(vphys_file, including_player_clippings=include_player_clippings) vphys_parser.to_tri(path=outpath) logger.success(f"Tri file saved to {outpath}") diff --git a/awpy/visibility.py b/awpy/visibility.py index c99103fd..675fa8e9 100644 --- a/awpy/visibility.py +++ b/awpy/visibility.py @@ -248,17 +248,19 @@ class VphysParser: the .vphys file. """ - def __init__(self, vphys_file: str | pathlib.Path) -> None: + def __init__(self, vphys_file: str | pathlib.Path, *, including_player_clippings: bool = False) -> None: """Initializes the parser with the path to a VPhys file. Args: vphys_file (str | pathlib.Path): Path to the VPhys file to parse. + including_player_clippings (bool, optional): Whether to include + player clippings in the generated triangles. Defaults to False. """ self.vphys_file = pathlib.Path(vphys_file) self.triangles = [] self.kv3_parser = KV3Parser() - self.parse() + self.parse(including_player_clippings=including_player_clippings) @staticmethod def bytes_to_vec(byte_str: str, element_size: int) -> list[int | float]: @@ -288,7 +290,9 @@ def bytes_to_vec(byte_str: str, element_size: int) -> list[int | float]: return result - def get_collision_attribute_indices_for_default_group(self) -> list[str]: + def get_collision_attribute_indices_for_default_group( + self, *, including_player_clippings: bool = False + ) -> list[str]: """Get collision attribute indices for the default group. Returns: @@ -302,14 +306,31 @@ def get_collision_attribute_indices_for_default_group(self) -> list[str]: break if collision_group_string.lower() == '"default"': collision_attribute_indices.append(str(idx)) + elif including_player_clippings: + relevant_interactions = ['"playerclip"'] + interacts_as: list[str] = [] + interact_idx = 0 + while True: + interaction = self.kv3_parser.get_value( + f"m_collisionAttributes[{idx}].m_InteractAsStrings[{interact_idx}]" + ) + if not interaction: + break + interacts_as.append(interaction) + interact_idx += 1 + if any(interaction.lower() in relevant_interactions for interaction in interacts_as): + collision_attribute_indices.append(str(idx)) idx += 1 return collision_attribute_indices - def parse(self) -> None: + def parse(self, *, including_player_clippings: bool = False) -> None: # noqa: PLR0912 """Parses the VPhys file and extracts collision geometry. Processes hulls and meshes in the VPhys file to generate a list of triangles. """ + if including_player_clippings: + logger.debug("Including player clippings in tri generation.") + if len(self.triangles) > 0: logger.debug(f"VPhys data already parsed, got {len(self.triangles)} triangles.") return @@ -323,7 +344,9 @@ def parse(self) -> None: # Parse VPhys data self.kv3_parser.parse(data) - collision_attribute_indices = self.get_collision_attribute_indices_for_default_group() + collision_attribute_indices = self.get_collision_attribute_indices_for_default_group( + including_player_clippings=including_player_clippings + ) logger.debug(f"Extracted collision attribute indices: {collision_attribute_indices}") diff --git a/scripts/generate-tris.ps1 b/scripts/generate-tris.ps1 index ec6fdd17..3949b151 100644 --- a/scripts/generate-tris.ps1 +++ b/scripts/generate-tris.ps1 @@ -79,6 +79,19 @@ Get-ChildItem -Path $inputPath -Filter "*.vpk" | Where-Object { Write-Host "Error: .tri output not created for $fileNameWithoutExtension" -ForegroundColor Red } + # Run the awpy tri command to generate a .tri file, outputting to a temporary file. + $triTempPath = Join-Path -Path $tempOutputDir -ChildPath "$fileNameWithoutExtension-clippings.tri" + Write-Host "Running awpy generate-tri on: $vphysFilePath" -ForegroundColor Yellow + uv run awpy tri $vphysFilePath --outpath $triTempPath --include_player_clippings + + if (Test-Path $triTempPath) { + $finalTriPath = Join-Path -Path $outputDirectory -ChildPath "$fileNameWithoutExtension-clippings.tri" + Move-Item -Path $triTempPath -Destination $finalTriPath -Force + Write-Host "Output saved as: $finalTriPath" -ForegroundColor Cyan + } else { + Write-Host "Error: .tri output not created for $fileNameWithoutExtension" -ForegroundColor Red + } + # Clean up the temporary directory. Remove-Item -Path $tempOutputDir -Recurse -Force }