From a0f2e7b6fd85030173bd4541368e5589ac708e2d Mon Sep 17 00:00:00 2001 From: coldino Date: Fri, 31 Jan 2020 15:41:21 +0000 Subject: [PATCH] Add species data to wiki export * First-pass currently extracts: * Basic info (name, blueprint, tags) * Drag weight and mass * Fall damage + speed * Walking and sprinting speeds This change also extends json formatting for neater attack info, but see #75 as this needs improving. --- ark/types.py | 17 ++++++ automate/config/sections.py | 1 + automate/jsonutils.py | 1 + automate/run.py | 3 ++ export/wiki/root.py | 2 + export/wiki/species/__init__.py | 0 export/wiki/species/attacks.py | 36 +++++++++++++ export/wiki/stage_species.py | 95 +++++++++++++++++++++++++++++++++ 8 files changed, 155 insertions(+) create mode 100644 export/wiki/species/__init__.py create mode 100644 export/wiki/species/attacks.py create mode 100644 export/wiki/stage_species.py diff --git a/ark/types.py b/ark/types.py index 6c8a644e..640c6cc2 100644 --- a/ark/types.py +++ b/ark/types.py @@ -74,6 +74,23 @@ class PrimalDinoCharacter(UEProxyStructure, uetype='/Script/ShooterGame.PrimalDi BoneDamageAdjusters: Mapping[int, ArrayProperty] # = [] # DevKit Unverified + MeleeDamageAmount = ueints(0) + MeleeSwingRadius = uefloats(0.0) + AttackInfos: Mapping[int, ArrayProperty] + + FallDamageMultiplier = uefloats(165.0) + MaxFallSpeed = uefloats(1200.0) + + Mass = uefloats(100.0) + DragWeight = uefloats(35.0) + + TargetingTeamNameOverride = uestrings('') + + MaxWalkSpeed = uefloats(600.0) + MaxWalkSpeedCrouched = uefloats(300.0) + MaxWalkSpeedProne = uefloats(100.0) + RunningSpeedModifier = uefloats(1.5) + bCanRun = uebools(False) class ShooterCharacterMovement(UEProxyStructure, uetype='/Script/ShooterGame.ShooterCharacterMovement'): diff --git a/automate/config/sections.py b/automate/config/sections.py index 9a9a893e..8413d4e6 100644 --- a/automate/config/sections.py +++ b/automate/config/sections.py @@ -85,6 +85,7 @@ class ExportWikiSection(ExportSection): ExportItems: bool = True ExportDrops: bool = True ExportLootCrates: bool = True + ExportSpecies: bool = True class Config: extra = Extra.forbid diff --git a/automate/jsonutils.py b/automate/jsonutils.py index 2404454d..130cd800 100644 --- a/automate/jsonutils.py +++ b/automate/jsonutils.py @@ -119,6 +119,7 @@ def _calculate_digest(values: Dict[str, Any]) -> Tuple[Optional[str], str]: JOIN_LINE_FIELDS = ( 'x|y|z', 'lat|long?', + 'name|interval|dmg|radius|stamina', ) diff --git a/automate/run.py b/automate/run.py index daf0af51..68e9f590 100644 --- a/automate/run.py +++ b/automate/run.py @@ -80,6 +80,7 @@ def create_parser() -> argparse.ArgumentParser: parser.add_argument('--skip-wiki-items', action='store_true', help='skip extracting items for the wiki') parser.add_argument('--skip-wiki-drops', action='store_true', help='skip extracting drops for the wiki') parser.add_argument('--skip-wiki-loot-crates', action='store_true', help='skip extracting loot crates for the wiki') + parser.add_argument('--skip-wiki-species', action='store_true', help='skip extracting species for the wiki') parser.add_argument('--skip-commit', action='store_true', help='skip git commit of the output repo (use dry-run mode)') parser.add_argument('--skip-pull', action='store_true', help='skip git pull or reset of the output repo') @@ -146,6 +147,8 @@ def handle_args(args: Any) -> ConfigFile: config.export_wiki.ExportDrops = False if args.skip_wiki_loot_crates: config.export_wiki.ExportLootCrates = False + if args.skip_wiki_species: + config.export_wiki.ExportSpecies = False # Git actions if args.skip_pull: diff --git a/export/wiki/root.py b/export/wiki/root.py index 386e26be..f908c37d 100644 --- a/export/wiki/root.py +++ b/export/wiki/root.py @@ -9,6 +9,7 @@ from .stage_loot_crates import LootCratesStage from .stage_maps import MapStage from .stage_spawn_groups import SpawnGroupStage +from .stage_species import SpeciesStage __all__ = [ 'WikiRoot', @@ -38,4 +39,5 @@ def __init__(self): ItemsStage(), DropsStage(), LootCratesStage(), + SpeciesStage(), ] diff --git a/export/wiki/species/__init__.py b/export/wiki/species/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/export/wiki/species/attacks.py b/export/wiki/species/attacks.py new file mode 100644 index 00000000..9c78bb30 --- /dev/null +++ b/export/wiki/species/attacks.py @@ -0,0 +1,36 @@ +from typing import * + +from ark.types import PrimalDinoCharacter +from ue.properties import StructProperty + + +def gather_attack_data(char: PrimalDinoCharacter): + result: Dict[str, Any] = dict() + + result['defaultDmg'] = char.MeleeDamageAmount[0] + result['defaultSwingRadius'] = char.MeleeSwingRadius[0] + + if 'AttackInfos' in char: + attacks = [_convert_attack(cast(StructProperty, attack)) for attack in char.AttackInfos[0].values] + if attacks: + result['attacks'] = attacks + + return dict(attack=result) + + +def _convert_attack(attack: StructProperty): + d: Dict[str, Any] = attack.as_dict() + + v = dict( + name=d['AttackName'] or None, + interval=d['AttackInterval'], + dmg=d['MeleeDamageAmount'], + radius=d['MeleeSwingRadius'], + stamina=d['StaminaCost'], + ) + + proj = d['ProjectileClass'] + if proj: + v['isProjectile'] = True + + return v diff --git a/export/wiki/stage_species.py b/export/wiki/stage_species.py new file mode 100644 index 00000000..cebceb0b --- /dev/null +++ b/export/wiki/stage_species.py @@ -0,0 +1,95 @@ +from logging import NullHandler, getLogger +from pathlib import PurePosixPath +from typing import * +from typing import cast + +from ark.asset import find_dcsc +from ark.overrides import OverrideSettings, get_overrides_for_species +from ark.types import DCSC, PrimalDinoCharacter +from automate.hierarchy_exporter import JsonHierarchyExportStage +from ue.asset import UAsset +from ue.gathering import gather_properties +from ue.proxy import UEProxyStructure +from ue.utils import clean_double as cd + +from .species.attacks import gather_attack_data + +__all__ = [ + 'SpeciesStage', +] + +logger = getLogger(__name__) +logger.addHandler(NullHandler()) + + +class SpeciesStage(JsonHierarchyExportStage): + def get_skip(self) -> bool: + return not self.manager.config.export_wiki.ExportSpecies + + def get_field(self): + return 'species' + + def get_use_pretty(self) -> bool: + return bool(self.manager.config.export_wiki.PrettyJson) + + def get_format_version(self): + return "1" + + def get_ue_type(self): + return PrimalDinoCharacter.get_ue_type() + + def extract(self, proxy: UEProxyStructure) -> Any: + species: PrimalDinoCharacter = cast(PrimalDinoCharacter, proxy) + + asset: UAsset = proxy.get_source().asset + assert asset.assetname and asset.default_class + modid: Optional[str] = self.manager.loader.get_mod_id(asset.assetname) + overrides = get_overrides_for_species(asset.assetname, modid) + + if _should_skip_species(species, overrides): + return None + + results: Dict[str, Any] = dict( + name=species.DescriptiveName[0], + blueprintPath=asset.default_class.fullname, + dinoNameTag=species.DinoNameTag[0], + customTag=species.CustomTag[0], + targetingTeamName=species.TargetingTeamNameOverride[0], + mass=species.Mass[0], + dragWeight=species.DragWeight[0], + ) + + results['falling'] = dict( + dmgMult=species.FallDamageMultiplier[0], + maxSpeed=species.MaxFallSpeed[0], + ) + + results['speed'] = species.MaxWalkSpeed[0] + if species.bCanRun[0]: + results['speedSprint'] = cd(species.MaxWalkSpeed[0] * species.RunningSpeedModifier[0]) + else: + results['speedSprint'] = None + + results.update(gather_attack_data(species)) + + return results + + +def _should_skip_species(species: PrimalDinoCharacter, overrides: OverrideSettings): + if overrides.skip_export: + return True + + if not species.has_override('DescriptiveName'): + return True + + # Check the local DCSC + dcsc_export = find_dcsc(species.get_source().asset) + if not dcsc_export: + return None + + # Check if there no overrides of MaxStatusValues + dcsc: DCSC = gather_properties(dcsc_export) # does not respect prioritising DCSCs, but that's okay here + if not any((not dcsc.has_override('MaxStatusValues', i)) for i in range(12)): + return True + + return False