예제 #1
0
파일: objects.py 프로젝트: kb173/srctools
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
예제 #2
0
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])
                )
예제 #3
0
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