From b3b121aab068a1181b894b07ecda225d4ca45b11 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 19 Sep 2023 13:15:01 +1000 Subject: [PATCH] Add new utility for adding visgrouped debugging ents to the final map. --- src/precomp/conditions/__init__.py | 79 ++++++++++++++++++++++++++- src/precomp/conditions/brushes.py | 38 +++++-------- src/precomp/conditions/positioning.py | 48 +++++++--------- src/precomp/tiling.py | 24 +++----- 4 files changed, 117 insertions(+), 72 deletions(-) diff --git a/src/precomp/conditions/__init__.py b/src/precomp/conditions/__init__.py index 3664e51d5..2a550ec44 100644 --- a/src/precomp/conditions/__init__.py +++ b/src/precomp/conditions/__init__.py @@ -42,12 +42,12 @@ from collections import defaultdict from decimal import Decimal from enum import Enum -from typing import Generic, TypeVar, Any, Callable, TextIO, Tuple, Type, overload, cast +from typing import Generic, Protocol, TypeVar, Any, Callable, TextIO, Tuple, Type, overload, cast import attrs import srctools.logger from srctools.math import AnyVec, FrozenAngle, Vec, FrozenVec, AnyAngle, AnyMatrix, Angle, Matrix -from srctools.vmf import VMF, Entity, Output, Solid +from srctools.vmf import EntityGroup, VMF, Entity, Output, Solid, ValidKVs, VisGroup from srctools import Keyvalues from precomp import instanceLocs, rand, collisions @@ -1018,7 +1018,80 @@ def local_name(inst: Entity, name: str | Entity) -> str: raise ValueError(f'Unknown fixup style {fixup}!') -def widen_fizz_brush(brush: Solid, thickness: float, bounds: tuple[Vec, Vec]=None): +class DebugAdder(Protocol): + @overload + def __call__(self, ent: Entity, /) -> Entity: + """Add this entity to the map, the visgroup and make it hidden.""" + + @overload + def __call__(self, brush: Solid, /) -> Entity: + """Add this brush to the map, the visgroup and make it hidden.""" + + @overload + def __call__(self, classname: str, /, *, comment: str='', **kwargs: ValidKVs) -> Entity: + """Create an entity with the specified keyvalues.""" + + +def fetch_debug_visgroup( + vmf: VMF, + vis_name: str, + r: int = 113, g: int = 113, b: int = 0, + force: bool = False, +) -> DebugAdder: + """If debugging is enabled, return a function that adds entities to the specified visgroup. + + * vis_name: The name of the visgroup to use. If already present the existing one is used. + * r, g, b: Color to use, if creating. + * force: If true, always adds. Otherwise, this only adds if Dev Mode is enabled. + + The returned function can either be called with a classname + keyvalues to create an ent, + or given an existing ent/brush to add. If given an existing ent/brush, it should not be + already added to the VMF - this will skip doing so if debugging is disabled. In that case + the ent/brush will just be discarded harmlessly. + """ + if not force and not utils.DEV_MODE: + def func(target: str | Entity | Solid, /, **kwargs: ValidKVs) -> Entity | Solid: + """Do nothing.""" + if isinstance(target, str): + # Create a dummy entity, which will be discarded. + return Entity(vmf, keys={'classname': target}) + return target + + return func + + for visgroup in vmf.vis_tree: + if visgroup.name == vis_name: + break + else: + # Create the visgroup. + visgroup = vmf.create_visgroup(vis_name, (r, g, b)) + + group = EntityGroup(vmf, color=Vec(r, g, b), shown=False) + + def adder(target: str | Entity | Solid, /, **kwargs: ValidKVs) -> Entity | Solid: + """Add a marker to the map.""" + if isinstance(target, str): + comment = kwargs.pop('comment', '') + target = vmf.create_ent(target, **kwargs) + target.comments = str(comment) + elif isinstance(target, Solid): + vmf.add_brush(target) + elif isinstance(target, Entity): + vmf.add_ent(target) + + target.visgroup_ids.add(visgroup.id) + if isinstance(target, Solid): + target.group_id = group.id + else: + target.groups.add(group.id) + target.vis_shown = False + target.hidden = True + return target + + return adder + + +def widen_fizz_brush(brush: Solid, thickness: float, bounds: tuple[Vec, Vec] | None = None) -> None: """Move the two faces of a fizzler brush outward. This is good to make fizzlers which are thicker than 2 units. diff --git a/src/precomp/conditions/brushes.py b/src/precomp/conditions/brushes.py index 1e1a44ffd..a9ae07f0c 100644 --- a/src/precomp/conditions/brushes.py +++ b/src/precomp/conditions/brushes.py @@ -861,13 +861,7 @@ def res_set_tile(inst: Entity, res: Keyvalues) -> None: else: rng = None - if utils.DEV_MODE: - try: - [visgroup] = [vis for vis in inst.map.vis_tree if vis.name == 'SetTile'] - except ValueError: - visgroup = inst.map.create_visgroup('SetTile') - else: - visgroup = None + debug_add = conditions.fetch_debug_visgroup(inst.map, 'SetTile') for y, row in enumerate(tiles): for x, val in enumerate(row): @@ -879,23 +873,19 @@ def res_set_tile(inst: Entity, res: Keyvalues) -> None: pos = Vec(32 * x, -32 * y, 0) @ orient + offset - if visgroup is not None: - try: - skin = template_brush.TILETYPE_TO_SKIN[tiling.TILETYPE_FROM_CHAR[val]] - except KeyError: - skin = 0 - trace = inst.map.create_ent( - 'bee2_template_tilesetter', - origin=pos, - angles=orient.to_angle(), - force=force_tile, - targetname=inst['targetname'], - skin=skin, - ) - trace.vis_shown = False - trace.hidden = True - trace.comments = f'This tile char [{x}, {y}] = {val}.' - trace.visgroup_ids.add(visgroup.id) + try: + skin = template_brush.TILETYPE_TO_SKIN[tiling.TILETYPE_FROM_CHAR[val]] + except KeyError: + skin = 0 + debug_add( + 'bee2_template_tilesetter', + origin=pos, + angles=orient.to_angle(), + force=force_tile, + targetname=inst['targetname'], + skin=skin, + comment=f'This tile char [{x}, {y}] = {val}.', + ) if val == '4': size = tiling.TileSize.TILE_4x4 diff --git a/src/precomp/conditions/positioning.py b/src/precomp/conditions/positioning.py index bebef56a7..5bdf505ac 100644 --- a/src/precomp/conditions/positioning.py +++ b/src/precomp/conditions/positioning.py @@ -2,15 +2,12 @@ import math from typing import Iterable, Tuple, Dict, Set, Callable -from srctools.vmf import EntityGroup - -import utils from precomp.conditions import ( make_flag, make_result, resolve_offset, DIRECTIONS, ) from editoritems_props import PanelAnimation -from precomp import tiling, brushLoc +from precomp import conditions, tiling, brushLoc from srctools import Vec, FrozenVec, Angle, Matrix, conv_float, Keyvalues, Entity from srctools.logger import get_logger @@ -117,35 +114,29 @@ def brush_at_loc( # Place info_targets to mark where we're checking. # These are hidden in a visgroup. debug_info = kv['debug', ''] - if utils.DEV_MODE: - try: - [visgroup] = [vis for vis in inst.map.vis_tree if vis.name == 'TileAtLoc'] - except ValueError: - visgroup = inst.map.create_visgroup('TileAtLoc') - first_trace = inst.map.create_ent('info_target', origin=pos, targetname=inst['targetname']) - first_trace.vis_shown = False - first_trace.hidden = True - first_trace.comments = debug_info - first_trace.visgroup_ids.add(visgroup.id) - else: - visgroup = first_trace = None + + # In dev mode, display a visual of this location. + debug_adder = conditions.fetch_debug_visgroup(inst.map, 'TileAtLoc') + + first_trace = debug_adder( + 'info_target', + origin=pos, + targetname=inst['targetname'], + comments=debug_info, + ) if 'pos2' in kv: pos2 = kv.vec('pos2') pos2.z -= 64 # Subtract so origin is the floor-position pos2.localise(origin, orient) - if visgroup is not None and first_trace is not None: - # Place a second for the bounding box, grouped with the first. - second_trace = inst.map.create_ent('info_target', origin=pos2, targetname=inst['targetname']) - second_trace.vis_shown = False - second_trace.hidden = True - second_trace.comments = debug_info - second_trace.visgroup_ids.add(visgroup.id) - group = EntityGroup(inst.map) - inst.map.groups[group.id] = group - first_trace.groups.add(group.id) - second_trace.groups.add(group.id) + # Place a second for the bounding box, grouped with the first. + debug_adder( + 'info_target', + origin=pos2, + targetname=inst['targetname'], + comments=debug_info, + ) bbox_min, bbox_max = Vec.bbox(round(pos, 6), round(pos2, 6)) @@ -190,8 +181,7 @@ def brush_at_loc( tile_types.add(tile_type) LOGGER.debug('PosIsSolid check {} - {} @ {} = {}', pos, pos2, norm, tile_types) - if first_trace is not None: - first_trace.comments += ' Tiles: ' + ' '.join([t.name for t in tile_types]) + first_trace.comments += ' Tiles: ' + ' '.join([t.name for t in tile_types]) if result_var: if tile_type.is_tile: diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index cf5ef9398..f1b61508d 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -501,6 +501,14 @@ def export( force_helper: bool, ) -> None: """Generate the panel brushes.""" + # In dev mode, display a visual of this location. + conditions.fetch_debug_visgroup(vmf, 'TilePanels')( + 'info_particle_system', + origin=tile.pos, + targetname=self.inst['targetname'], + angles=tile.normal, + comment=tile.format_tiles().replace('\n', ', ') + ) # We need to do the checks to handle multiple panels with shared # data. if all(subtile is TileType.VOID for subtile in sub_tiles.values()): @@ -508,22 +516,6 @@ def export( # The brush entity isn't used. if self.brush_ent in vmf.entities: self.brush_ent.remove() - # In dev mode, display a visual of this location. - if utils.DEV_MODE: - try: - [visgroup] = [vis for vis in vmf.vis_tree if vis.name == 'TilePanels'] - except ValueError: - visgroup = vmf.create_visgroup('TilePanels') - panel_trace = vmf.create_ent( - 'info_particle_system', - origin=tile.pos, - targetname=self.inst['targetname'], - angles=tile.normal.to_angle(), - ) - panel_trace.comments = tile.format_tiles().replace('\n', ', ') - panel_trace.vis_shown = False - panel_trace.hidden = True - panel_trace.visgroup_ids.add(visgroup.id) return else: # We do use it.