def parse( vmf: VMF, pack: PackList ) -> Tuple[int, Dict[Tuple[str, str, int], VacObject], Dict[str, str], ]: """Parse out the cube objects from the map. The return value is the number of objects, a dict of objects, and the filenames of the script generated for each group. The dict is (group, model, skin) -> object. """ cube_objects: Dict[Tuple[str, str, int], VacObject] = {} vac_objects: Dict[str, List[VacObject]] = defaultdict(list) for i, ent in enumerate(vmf.by_class['comp_vactube_object']): offset = Vec.from_str(ent['origin']) - Vec.from_str(ent['offset']) obj = VacObject( f'obj_{i:x}', ent['group'], ent['model'], ent['cube_model'], offset, srctools.conv_int(ent['weight']), srctools.conv_int(ent['tv_skin']), srctools.conv_int(ent['cube_skin']), srctools.conv_int(ent['skin']), ) vac_objects[obj.group].append(obj) # Convert the ent into a precache ent, stripping the other keyvalues. ent.keys = {'model': ent['model']} make_precache_prop(ent) if obj.model_drop: cube_objects[obj.group, obj.model_drop.replace('\\', '/'), obj.skin_drop, ] = obj # Generate and pack the vactube object scripts. # Each group is the same, so it can be shared among them all. codes = {} for group in sorted(vac_objects): code = [] for i, obj in enumerate(vac_objects[group]): if obj.model_drop: model_code = f'"{obj.model_drop}"' else: model_code = 'null' code.append( f'{obj.id} <- obj("{obj.model_vac}", {obj.skin_vac}, ' f'{model_code}, {obj.weight}, "{obj.offset}", {obj.skin_tv});') codes[group] = pack.inject_vscript('\n'.join(code)) return len(vac_objects), cube_objects, codes
def run_transformations( vmf: VMF, filesys: FileSystem, pack: PackList, bsp: BSP, game: Game, studiomdl_loc: Path=None, ) -> None: """Run all transformations.""" context = Context(filesys, vmf, pack, bsp, game, studiomdl_loc=studiomdl_loc) for func_name, func in sorted( TRANSFORMS.items(), key=lambda tup: tup[1].priority, ): LOGGER.info('Running "{}"...', func_name) func(context) if context._ent_code: LOGGER.info('Injecting VScript code...') for ent, code in context._ent_code.items(): init_scripts = ent['vscripts'].split() init_scripts.append(pack.inject_vscript(code.replace('`', '"'))) ent['vscripts'] = ' '.join(init_scripts) if context._io_remaps: LOGGER.info('Remapping outputs...') for ent in vmf.entities: todo = ent.outputs[:] # Recursively convert only up to 500 times. # Arbitrary limit, should be sufficient. for _ in range(500): if not todo: break deferred = [] for out in todo: try: remaps, should_remove = context._io_remaps[ out.target.casefold(), out.input.casefold(), ] except KeyError: continue if should_remove: ent.outputs.remove(out) for rep_out in remaps: new_out = Output( out.output, rep_out.target, rep_out.input, rep_out.params or out.params, out.delay + rep_out.delay, only_once=rep_out.only_once and out.only_once, ) ent.outputs.append(new_out) deferred.append(new_out) todo = deferred else: LOGGER.error( 'Entity "{}" ({}) has infinite loop when expanding ' ' compiler outputs to real ones! Final output list: \n{}', ent['targetname'], ent['classname'], '\n'.join(['* {}\n'.format(out) for out in ent.outputs]) )
def parse( vmf: VMF, pack: PackList ) -> Tuple[int, Dict[Tuple[str, str, int], VacObject], Dict[str, str], ]: """Parse out the cube objects from the map. The return value is the number of objects, a dict of objects, and the filenames of the script generated for each group. The dict is (group, model, skin) -> object. """ cube_objects: Dict[Tuple[str, str, int], VacObject] = {} vac_objects: Dict[str, List[VacObject]] = defaultdict(list) for i, ent in enumerate(vmf.by_class['comp_vactube_object']): offset = Vec.from_str(ent['origin']) - Vec.from_str(ent['offset']) obj = VacObject( f'obj_{i:x}', ent['group'], ent['model'], ent['cube_model'], offset, srctools.conv_int(ent['weight']), srctools.conv_int(ent['tv_skin']), srctools.conv_int(ent['cube_skin']), srctools.conv_int(ent['skin']), ) vac_objects[obj.group].append(obj) # Convert the ent into a precache ent, stripping the other keyvalues. mdl_name = ent['model'] ent.keys = {'model': mdl_name} make_precache_prop(ent) pack.pack_file(mdl_name, FileType.MODEL, skinset={obj.skin_vac}) if obj.model_drop: cube_objects[obj.group, obj.model_drop.replace('\\', '/'), obj.skin_drop, ] = obj # Generate and pack the vactube object scripts. # Each group is the same, so it can be shared among them all. codes = {} for group, objects in sorted(vac_objects.items(), key=lambda t: t[0]): # First, see if there's a common multiple among the weights, allowing # us to simplify. multiple = objects[0].weight for obj in objects[1:]: multiple = math.gcd(multiple, obj.weight) if multiple > 1: LOGGER.info('Group "{}" has common factor of {}, simplifying.', group, multiple) code = [] for i, obj in enumerate(objects): obj.weight /= multiple if obj.model_drop: model_code = f'"{obj.model_drop}"' else: model_code = 'null' code.append( f'{obj.id} <- obj("{obj.model_vac}", {obj.skin_vac}, ' f'{model_code}, {obj.weight}, "{obj.offset}", {obj.skin_tv});') codes[group] = pack.inject_vscript('\n'.join(code)) return len(vac_objects), cube_objects, codes