Example #1
0
def explore_path(path: str, loader: AssetLoader, excludes: Iterable[str], verbose=False, disable_debug=False):
    '''Run hierarchy discovery over every matching asset within the given path.'''
    excludes = set(excludes)

    logger.info('Discovering hierarchy in path: %s', path)

    n = 0

    with ue_parsing_context(properties=False):
        asset_iterator = loader.find_assetnames('.*', path, exclude=excludes, extension=asset_extensions, return_extension=True)
        for (assetname, ext) in asset_iterator:
            n += 1
            if verbose and n % 200 == 0: logger.info(assetname)

            try:
                asset = loader.load_asset(assetname, quiet=disable_debug)
            except AssetLoadException:
                logger.warning("Failed to load asset: %s", assetname)
                continue

            try:
                _ingest_asset(asset, loader, ext)
            except AssetLoadException:
                logger.warning("Failed to check parentage of %s", assetname)
            except MissingParent as ex:
                logger.exception("Missing parent for %s", assetname)
                raise MissingParent from ex

            # Remove maps from the cache immediately as they are large and cannot be inherited from
            if ext == '.umap':
                loader.cache.remove(assetname)
Example #2
0
def gather_results(loader: AssetLoader, path: str,
                   **kwargs) -> Tuple[Set[str], Set[str]]:
    kwargs.setdefault('extension', ['.txt'])
    if 'invert' in kwargs:
        raise ValueError('invert cannot appear in kwargs')
    normal = set(loader.find_assetnames(path, **kwargs))
    inverted = set(loader.find_assetnames(path, **kwargs, invert=True))
    return (normal, inverted)
Example #3
0
def test_defaults(loader: AssetLoader):
    loader.wipe_cache()
    asset = loader[TEST_PGD_PKG]
    assert asset.is_linked
    assert asset.has_properties
    assert not asset.has_bulk_data

    loader.wipe_cache()
    with ue_parsing_context():
        asset = loader[TEST_PGD_PKG]
        assert asset.is_linked
        assert asset.has_properties
        assert not asset.has_bulk_data
Example #4
0
def test_bulk_data(loader: AssetLoader):
    loader.wipe_cache()
    with ue_parsing_context(bulk_data=False):
        asset = loader[TEST_PGD_PKG]
        assert not asset.has_bulk_data

        # Check asset is re-parsed when more data is requested
        with ue_parsing_context(bulk_data=True):
            asset = loader[TEST_PGD_PKG]
            assert asset.has_bulk_data

    loader.wipe_cache()
    with ue_parsing_context(bulk_data=True):
        asset = loader[TEST_PGD_PKG]
        assert asset.has_bulk_data
Example #5
0
def test_properties(loader: AssetLoader):
    loader.wipe_cache()
    with ue_parsing_context(properties=False):
        asset = loader[TEST_PGD_PKG]
        assert not asset.has_properties

        # Check asset is re-parsed when more data is requested
        with ue_parsing_context(properties=True):
            asset = loader[TEST_PGD_PKG]
            assert asset.has_properties

    loader.wipe_cache()
    with ue_parsing_context(properties=True):
        asset = loader[TEST_PGD_PKG]
        assert asset.has_properties
Example #6
0
def test_linking(loader: AssetLoader):
    loader.wipe_cache()
    with ue_parsing_context(link=False):
        asset = loader[TEST_PGD_PKG]
        assert not asset.is_linked

        # Check asset is re-parsed when more data is requested
        with ue_parsing_context(link=True):
            asset = loader[TEST_PGD_PKG]
            assert asset.is_linked

    loader.wipe_cache()
    with ue_parsing_context(link=True):
        asset = loader[TEST_PGD_PKG]
        assert asset.is_linked
Example #7
0
def gather_breeding_data(props, loader: AssetLoader) -> Dict[str, Any]:
    data: Dict[str, Any] = dict(gestationTime=0, incubationTime=0)

    gestation_breeding = stat_value(props, 'bUseBabyGestation', 0, False)
    has_eggs = False

    if props['FertilizedEggItemsToSpawn'][0] and props[
            'FertilizedEggItemsToSpawn'][0][-1].values:
        # eggs = list(filter(lambda v: v and str(v) != 'None', props['FertilizedEggItemsToSpawn'][0][-1].values))
        eggs = [
            egg for egg in props['FertilizedEggItemsToSpawn'][0][-1].values
            if str(egg) != 'None'
        ]
        has_eggs = bool(eggs)

    if gestation_breeding:
        gestation_speed = stat_value(props, 'BabyGestationSpeed', 0,
                                     BABYGESTATIONSPEED_DEFAULT)
        extra_gestation_speed_m = stat_value(
            props, 'ExtraBabyGestationSpeedMultiplier', 0, 1.0)

        # TODO: Verify if these should really default to 1 - seems odd
        gestation_speed = gestation_speed or 1
        extra_gestation_speed_m = extra_gestation_speed_m or 1
        # 'gestationTime' = 1 / (Baby Gestation Speed × Extra Baby Gestation Speed Multiplier)
        data['gestationTime'] = (
            1 / gestation_speed / extra_gestation_speed_m
        ) if gestation_speed and extra_gestation_speed_m else None

    elif has_eggs:
        fert_egg_asset = loader.load_related(eggs[0])
        fert_egg_props = ark.mod.gather_properties(fert_egg_asset)
        egg_decay = stat_value(fert_egg_props, 'EggLoseDurabilityPerSecond', 0,
                               1)
        extra_egg_decay_m = stat_value(
            fert_egg_props, 'ExtraEggLoseDurabilityPerSecondMultiplier', 0, 1)

        # 'incubationTime' = 100 / (Egg Lose Durability Per Second × Extra Egg Lose Durability Per Second Multiplier)
        data['incubationTime'] = (
            100 / egg_decay /
            extra_egg_decay_m) if egg_decay and extra_egg_decay_m else None
        data['eggTempMin'] = stat_value(fert_egg_props, 'EggMinTemperature', 0)
        data['eggTempMax'] = stat_value(fert_egg_props, 'EggMaxTemperature', 0)

    # 'maturationTime' = 1 / (Baby Age Speed × Extra Baby Age Speed Multiplier)
    baby_age_speed = stat_value(props, 'BabyAgeSpeed', 0, 1)
    extra_baby_age_speed_m = stat_value(props, 'ExtraBabyAgeSpeedMultiplier',
                                        0, 1)

    data['maturationTime'] = (
        1 / baby_age_speed / extra_baby_age_speed_m
    ) if baby_age_speed and extra_baby_age_speed_m else None
    data['matingCooldownMin'] = stat_value(
        props, 'NewFemaleMinTimeBetweenMating', 0,
        FEMALE_MINTIMEBETWEENMATING_DEFAULT)
    data['matingCooldownMax'] = stat_value(
        props, 'NewFemaleMaxTimeBetweenMating', 0,
        FEMALE_MAXTIMEBETWEENMATING_DEFAULT)

    return data
Example #8
0
def gather_pgd_colors(props: PriorityPropDict, loader: AssetLoader,
                      require_override=True) -> Tuple[Optional[Sequence[ColorEntry]], Optional[Sequence[ColorEntry]]]:
    '''Gather color and dye definitions from a PrimalGameData asset.'''
    colors: Optional[List[ColorEntry]] = list()
    dyes: Optional[List[ColorEntry]] = list()

    # Collect the color definitions
    color_def_overrides = props['ColorDefinitions'][0]
    if require_override and len(color_def_overrides) == 1:
        colors = None
    else:
        color_defs = color_def_overrides[-1].values
        colors = list()
        for definition in ((entry.as_dict() for entry in color_defs)):
            name = definition.get('ColorName', None) or '~~unset~~'
            value = definition.get('ColorValue', None)
            color = value.values[0].as_tuple() if value else None
            colors.append((str(name), color))

    # Collect the dye definitions
    dye_def_overrides = props['MasterDyeList'][0]
    if require_override and len(dye_def_overrides) == 1:
        dyes = None
    else:
        dye_defs = props['MasterDyeList'][0][-1].values
        dyes = list()
        for dye_asset in (loader.load_related(entry) for entry in dye_defs):
            dye_props = gather_properties(dye_asset)
            name = stat_value(dye_props, 'DescriptiveNameBase', 0, None) or '~~unset~~'
            value = dye_props['DyeColor'][0][-1]
            color = value.values[0].as_tuple() if value else None
            dyes.append((str(name), color))

    return (colors, dyes)
Example #9
0
def fixture_simple_loader() -> AssetLoader:
    loader = AssetLoader(
        assetpath=DATA_PATH,
        modresolver=MockModResolver(),
        cache_manager=MockCacheManager(),
        rewrites={},
        mod_aliases={},
    )
    return loader
Example #10
0
def get_species_from_mod(asset: UAsset, loader: AssetLoader = None) -> list:
    loader = loader or asset.loader
    assert loader and asset.assetname
    this_mod = loader.get_mod_name(asset.assetname)
    mod_species = set()

    # Gather species from the remapped NPCs list
    for _, toPkg in get_mod_remapped_npcs(asset):
        to_mod = loader.get_mod_name(toPkg)
        if to_mod == this_mod:
            mod_species.add(toPkg)

    # Gather species from the remapped spawn zones
    for _, toPkgs in get_mod_remapped_spawners(asset):
        for toPkg in toPkgs:
            to_mod = loader.get_mod_name(toPkg)
            if to_mod == this_mod:
                mod_species.add(toPkg)

    return sorted(list(mod_species))
Example #11
0
 def _fetchModTitleFromPGD(self, moddata):
     resolver = FixedModResolver({moddata['name']: moddata['id']})
     loader = AssetLoader(resolver, self.asset_path)
     pkg = moddata['package']
     if pkg:
         pgd_asset = loader[moddata['package']]
         title = pgd_asset.default_export.properties.get_property(
             'ModName').value
     else:
         title = moddata['id']
     return title
Example #12
0
    def _fetch_mod_title_from_pgd(self, moddata):
        resolver = FixedModResolver({moddata['name']: moddata['id']})
        loader = AssetLoader(modresolver=resolver, assetpath=self.asset_path)
        pkg = moddata['package']

        if pkg:
            pgd_asset = loader[moddata['package']]
            title = pgd_asset.default_export.properties.get_property('ModName', fallback=None)
            if title:
                return str(title)

        return None
Example #13
0
 def createLoader(self) -> AssetLoader:
     '''Create an asset loader pointing at the managed game install.'''
     rewrites = get_overrides().rewrites.assets or dict()
     mod_aliases = self.config.combine_mods.src_to_aliases
     modresolver = ManagedModResolver(self)
     loader = AssetLoader(
         modresolver=modresolver,
         assetpath=self.asset_path,
         rewrites=rewrites,
         mod_aliases=mod_aliases,
     )
     return loader
Example #14
0
def _ingest_export(export: ExportTableItem, loader: AssetLoader):
    current_cls: ExportTableItem = export

    segment: Optional[Node[str]] = None
    fullname = current_cls.fullname
    assert fullname

    # We may have already covered this while traversing parents
    if fullname in tree:
        return

    while True:
        # Extend unsaved segment
        old_segment = segment
        segment = Node(fullname)
        if old_segment:
            segment.add(old_segment)

        # Get name of parent class
        parent_name = _get_parent_cls(current_cls)
        if not parent_name:
            raise MissingParent(f'Unable to find parent of {fullname}')

        # Is the parent present in the tree?
        anchor_point = tree.get(parent_name, None)

        # If we've risen outside /Game but didn't find a match, add it to the root and complain
        if not anchor_point and not parent_name.startswith('/Game'):
            logger.warning(
                f'Internal class {parent_name} missing from pre-defined hierarchy'
            )
            tree.add(ROOT_NAME, parent_name)
            anchor_point = tree.get(parent_name, None)

        if anchor_point:
            # Insert segment and finish
            tree.insert_segment(parent_name, segment)
            return

        # Load parent class and replace current
        parent_cls = loader.load_class(parent_name)
        current_cls = parent_cls
        fullname = current_cls.fullname
        assert fullname
Example #15
0
def gather_pgd_colors(
    asset: UAsset,
    props: PrimalGameData,
    loader: AssetLoader,
    require_override=True
) -> Tuple[Optional[Sequence[ColorEntry]], Optional[Sequence[ColorEntry]]]:
    '''Gather color and dye definitions from a PrimalGameData asset.'''
    colors: Optional[List[ColorEntry]] = list()
    dyes: Optional[List[ColorEntry]] = list()

    # Collect the color definitions
    color_def_overrides = props.ColorDefinitions[0]
    if require_override and color_def_overrides.asset != asset:
        colors = None
    else:
        color_defs = color_def_overrides.values
        colors = list()
        for definition in ((entry.as_dict() for entry in color_defs)):
            name = definition.get('ColorName', None) or '~~unset~~'
            value = definition.get('ColorValue', None)
            color = value.values[0].as_tuple() if value else None
            colors.append((str(name), color))

    # Collect the dye definitions
    dye_def_overrides = props.MasterDyeList[0]
    if require_override and dye_def_overrides.asset != asset:
        dyes = None
    else:
        dye_defs = dye_def_overrides.values
        dyes = list()
        for dye_asset in (loader.load_related(entry) for entry in dye_defs):
            assert dye_asset and dye_asset.default_export
            dye_props: PrimalItem_Dye = ue.gathering.gather_properties(
                dye_asset.default_export)
            name = dye_props.DescriptiveNameBase[0] or '~~unset~~'
            value = dye_props.DyeColor[0]
            color = value.values[0].as_tuple() if value else None
            dyes.append((str(name), color))

    return (colors, dyes)
Example #16
0
def gather_breeding_data(char_props: PrimalDinoCharacter,
                         loader: AssetLoader) -> Dict[str, Any]:
    data: Dict[str, Any] = dict(gestationTime=0, incubationTime=0)

    gestation_breeding = char_props.bUseBabyGestation[0]
    fert_eggs = char_props.get('FertilizedEggItemsToSpawn', 0, None)
    fert_egg_weights = char_props.get('FertilizedEggWeightsToSpawn', 0, None)

    if gestation_breeding:
        gestation_speed = char_props.BabyGestationSpeed[0].rounded_value
        extra_gestation_speed_m = char_props.ExtraBabyGestationSpeedMultiplier[
            0].rounded_value
        try:
            data['gestationTime'] = cd(1 / gestation_speed /
                                       extra_gestation_speed_m)
        except ZeroDivisionError:
            logger.warning(
                f"Species {char_props.get_source().asset.assetname} tried dividing by zero for its gestationTime"
            )

    elif fert_eggs and fert_eggs.values:
        eggs: List[Tuple[ObjectProperty, float]] = []
        for index, egg in enumerate(fert_eggs.values):
            weight = fert_egg_weights.values[index] if fert_egg_weights else 1
            # Verify the egg is a valid Object and that weight isn't 0
            if str(egg) == 'None' or weight == 0:
                continue

            eggs.append((egg, weight))

        # Sort eggs by highest weighting
        eggs.sort(reverse=True, key=itemgetter(1))

        if eggs:
            # We only provide the highest possibility egg to ASB
            fert_egg_asset = loader.load_related(eggs[0][0])
            assert fert_egg_asset.default_export
            egg_props: PrimalItem = ue.gathering.gather_properties(
                fert_egg_asset.default_export)
            egg_decay = egg_props.EggLoseDurabilityPerSecond[0].rounded_value
            extra_egg_decay_m = egg_props.ExtraEggLoseDurabilityPerSecondMultiplier[
                0].rounded_value

            # 'incubationTime' = 100 / (Egg Lose Durability Per Second × Extra Egg Lose Durability Per Second Multiplier)
            try:
                data['incubationTime'] = cd(100 / egg_decay /
                                            extra_egg_decay_m)
            except ZeroDivisionError:
                logger.warning(
                    f"Species {char_props.get_source().asset.assetname} tried dividing by zero for its incubationTime"
                )
            data['eggTempMin'] = egg_props.EggMinTemperature[0]
            data['eggTempMax'] = egg_props.EggMaxTemperature[0]

    # 'maturationTime' = 1 / (Baby Age Speed × Extra Baby Age Speed Multiplier)
    baby_age_speed = char_props.BabyAgeSpeed[0].rounded_value
    extra_baby_age_speed_m = char_props.ExtraBabyAgeSpeedMultiplier[
        0].rounded_value

    try:
        data['maturationTime'] = cd(1 / baby_age_speed /
                                    extra_baby_age_speed_m)
    except ZeroDivisionError:
        logger.warning(
            f"Species {char_props.get_source().asset.assetname} tried dividing by zero for its maturationTime"
        )
    data['matingCooldownMin'] = char_props.NewFemaleMinTimeBetweenMating[0]
    data['matingCooldownMax'] = char_props.NewFemaleMaxTimeBetweenMating[0]

    return data
Example #17
0
def test_no_properties_without_link(loader: AssetLoader):
    loader.wipe_cache()
    with ue_parsing_context(link=False, properties=True):
        asset = loader[TEST_PGD_PKG]
        assert not asset.has_properties
Example #18
0
 def createLoader(self) -> AssetLoader:
     '''Create an asset loader pointing at the managed game install.'''
     modresolver = ManagedModResolver(self)
     loader = AssetLoader(modresolver, self.asset_path)
     return loader