Skip to content

Commit 8eb8438

Browse files
committed
Add an option to allow the sources for compiled models to be preserved.
1 parent 45a30cb commit 8eb8438

6 files changed

Lines changed: 62 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Limit the size of propcombined groups to avoid hitting vertex limits.
88
* Prevent automatically packing models specified only as Hammer previews in various entities.
99
* Fix propcombine sometimes removing collisions entirely from component props.
10+
* Add an option to allow the sources for compiled models to be preserved.
1011

1112
--------------------
1213

src/hammeraddons/bsp_transform/__init__.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ def __init__(
4747
bsp: BSP,
4848
game: Game,
4949
*,
50-
studiomdl_loc: Optional[Path]=None,
51-
tags: FrozenSet[str]=frozenset(),
50+
studiomdl_loc: Optional[Path] = None,
51+
tags: FrozenSet[str] = frozenset(),
52+
modelcompile_dump: Optional[Path] = None,
5253
) -> None:
5354
self.sys = filesys
5455
self.vmf = vmf
@@ -57,6 +58,7 @@ def __init__(
5758
self.bsp_path = Path(bsp.filename)
5859
self._fgd: Optional[FGD] = None
5960
self.tags = tags
61+
self.modelcompile_dump = modelcompile_dump
6062
self.game = game
6163
self.studiomdl = studiomdl_loc
6264
self.config = Keyvalues.root()
@@ -147,12 +149,17 @@ async def run_transformations(
147149
pack: PackList,
148150
bsp: BSP,
149151
game: Game,
150-
studiomdl_loc: Optional[Path]=None,
151-
config: Mapping[str, Keyvalues]=EmptyMapping,
152+
studiomdl_loc: Optional[Path] = None,
153+
config: Mapping[str, Keyvalues] = EmptyMapping,
152154
tags: FrozenSet[str] = frozenset(),
155+
modelcompile_dump: Optional[Path] = None,
153156
) -> None:
154157
"""Run all transformations."""
155-
context = Context(filesys, vmf, pack, bsp, game, studiomdl_loc=studiomdl_loc, tags=tags)
158+
context = Context(
159+
filesys, vmf, pack, bsp, game,
160+
studiomdl_loc=studiomdl_loc, tags=tags,
161+
modelcompile_dump=modelcompile_dump,
162+
)
156163

157164
for func_name, func in sorted(
158165
TRANSFORMS.items(),

src/hammeraddons/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,12 @@ def packfile_filters(block: Keyvalues, kind: str) -> Iterator[re_Pattern[str]]:
372372
""",
373373
)
374374

375+
MODEL_COMPILE_DUMP = Opt.string(
376+
'modelcompile_dump', '',
377+
"""If set, models will be compiled as subfolders of this folder, instead of in a
378+
temporary directory.
379+
""")
380+
375381
USE_COMMA_SEP = Opt.boolean_or_none(
376382
'use_comma_sep',
377383
"""Before L4D, entity I/O used ',' to seperate the different parts.

src/hammeraddons/mdl_compiler.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
Each comes with a key, used to identify a previously compiled version.
44
We can then reuse already compiled versions.
55
"""
6-
from typing import Any, Awaitable, Callable, Generic, Hashable, List, Set, Tuple, TypeVar
6+
import shutil
7+
from typing import (
8+
Any, Awaitable, Callable, Generic, Hashable, List, Optional, Set, Tuple, TypeVar,
9+
ContextManager, Union,
10+
)
711
from typing_extensions import Self
812
from pathlib import Path
913
import os
1014
import pickle
1115
import random
1216
import tempfile
17+
import contextlib
1318

1419
from srctools import AtomicWriter, logger
1520
from srctools.game import Game
@@ -52,6 +57,7 @@ def __init__(
5257
folder_name: str,
5358
version: object=0,
5459
pack_models: bool=True,
60+
compile_dir: Optional[Path] =None,
5561
) -> None:
5662
# The models already constructed.
5763
self._built_models: ACache[ModelKey, GenModel[OutT]] = ACache()
@@ -65,6 +71,7 @@ def __init__(
6571
self.pack: PackList = pack
6672
self.version = version
6773
self.studiomdl_loc = studiomdl_loc
74+
self.compile_dir = (compile_dir / folder_name) if compile_dir is not None else None
6875
self.limiter = trio.CapacityLimiter(8)
6976
self.pack_models = pack_models
7077
# For statistics, the number we built this compile
@@ -82,6 +89,7 @@ def from_ctx(cls, ctx: Context, folder_name: str, version: object=0) -> 'ModelCo
8289
ctx.bsp_path.stem,
8390
folder_name,
8491
version,
92+
compile_dir=ctx.modelcompile_dump,
8593
)
8694

8795
def use_count(self) -> int:
@@ -225,7 +233,20 @@ async def _compile(
225233
self._mdl_names.add(mdl_name)
226234
break
227235

228-
with tempfile.TemporaryDirectory(prefix='mdl_compile') as folder:
236+
# If compile dir is specified, create the folder/clear it, but don't delete once done.
237+
ctx_man: ContextManager[Union[str, bytes, Path]]
238+
if self.compile_dir is not None:
239+
path = Path(self.compile_dir, mdl_name)
240+
ctx_man = contextlib.nullcontext(path)
241+
try:
242+
shutil.rmtree(path)
243+
except FileNotFoundError:
244+
pass
245+
path.mkdir(parents=True, exist_ok=True)
246+
else: # If not specified, use a temporary directory.
247+
ctx_man = tempfile.TemporaryDirectory(prefix='mdl_compile')
248+
249+
with ctx_man as folder:
229250
path = Path(folder)
230251
result = await compile_func(key, path, f'{self.model_folder}{mdl_name}.mdl', args)
231252
studio_args = [
@@ -237,6 +258,8 @@ async def _compile(
237258
LOGGER.debug("Execute {}", studio_args)
238259
async with self.limiter:
239260
res = await trio.run_process(studio_args, capture_stdout=True, check=False)
261+
if self.compile_dir is not None:
262+
(path / 'compile.log').write_bytes(res.stdout)
240263
LOGGER.debug(
241264
'Log for {}:\n{}',
242265
str(path / 'model.qc'),

src/hammeraddons/postcompiler.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Runs before VRAD, to run operations on the final BSP."""
2+
import shutil
23
from pathlib import Path
34
import sys
45
import warnings
@@ -20,7 +21,6 @@
2021

2122
from srctools import __version__ as version_lib, conv_bool
2223
from srctools.bsp import BSP
23-
from srctools.fgd import FGD
2424
from srctools.filesys import ZipFileSystem
2525
from srctools.packlist import PackList
2626

@@ -139,6 +139,19 @@ async def main(argv: List[str]) -> None:
139139
LOGGER.warning('No studiomdl path provided.')
140140
studiomdl_loc = None
141141

142+
modelcompile_dump_str = conf.opts.get(config.MODEL_COMPILE_DUMP)
143+
modelcompile_dump = conf.expand_path(modelcompile_dump_str) if modelcompile_dump_str else None
144+
if modelcompile_dump is not None:
145+
LOGGER.info('Clearing model compile dump folder {}', modelcompile_dump)
146+
try:
147+
for file in modelcompile_dump.iterdir():
148+
if file.is_dir():
149+
shutil.rmtree(file)
150+
else:
151+
file.unlink()
152+
except FileNotFoundError:
153+
pass # Already empty.
154+
142155
use_comma_sep = conf.opts.get(config.USE_COMMA_SEP)
143156
if use_comma_sep is None:
144157
# Guess the format, by checking existing outputs.
@@ -176,6 +189,7 @@ async def main(argv: List[str]) -> None:
176189
studiomdl_loc,
177190
transform_conf,
178191
pack_tags,
192+
modelcompile_dump=modelcompile_dump,
179193
)
180194

181195
if studiomdl_loc is not None and args.propcombine:
@@ -211,6 +225,7 @@ async def main(argv: List[str]) -> None:
211225
min_cluster=conf.opts.get(config.PROPCOMBINE_MIN_CLLUSTER),
212226
blacklist=conf.opts.get(config.PROPCOMBINE_BLACKLIST).as_array(),
213227
volume_tolerance=conf.opts.get(config.PROPCOMBINE_VOLUME_TOLERANCE),
228+
compile_dump=modelcompile_dump,
214229
debug_dump=args.dumpgroups,
215230
pack_models=conf.opts.get(config.PROPCOMBINE_PACK) or False,
216231
)

src/hammeraddons/propcombine.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,7 @@ async def combine(
10641064
qc_folders: Optional[List[Path]]=None,
10651065
crowbar_loc: Optional[Path]=None,
10661066
decomp_cache_loc: Optional[Path]=None,
1067+
compile_dump: Optional[Path]=None,
10671068
blacklist: Iterable[str]=(),
10681069
auto_range: float=0,
10691070
min_cluster: int=2,
@@ -1266,6 +1267,7 @@ def get_grouping_key(prop: StaticProp) -> Optional[tuple]:
12661267
'ver': 2,
12671268
'vol_tolerance': volume_tolerance,
12681269
},
1270+
compile_dir=compile_dump,
12691271
pack_models=pack_models,
12701272
) as compiler:
12711273
async def do_combine(group: List[StaticProp]) -> None:

0 commit comments

Comments
 (0)