mora-kid: activate trait predicates (Plan 8b)#47
Merged
Conversation
Completes KID filter grammar coverage for Weapon + Armor rules by activating trait predicates (OneHandSword, HEAVY, -E, D(min max), AR(min max), body slots, etc.). Extends mora-esp's WeaponRecord + ArmorRecord with DATA/DNAM/EITM/ CNAM/TNAM/BOD2/BODT subrecord parsing. Adds WeaponAnimType + ArmorType + BipedObject types. mora-kid gains evaluate_weapon_traits + evaluate_armor_traits helpers that the distributor calls in place of the previous log-and-skip stubs. 11 tasks across 10 phases. ~14 new tests (9 subrecord units + 6 trait integration). Target test total ~195. Note: ARMO template is TNAM, not CNAM like WEAP — common bug caught during research.
Appends byte-layout tables for WEAP DATA/DNAM/EITM/CNAM and ARMO DATA/DNAM/EITM/TNAM/BOD2/BODT. Animation-type + armor-type enum values. Body-slot bitmask conventions. Cited by every parser task in Plan 8b.
Signature consts: DNAM, EITM, CNAM, TNAM, BOD2, BODT. Shared subrecords::form_id_ref::parse returns the raw u32 for later remapping by EspWorld::resolve_in_plugin. Used by EITM (enchant refs), CNAM (weapon template), TNAM (armor template).
weapon_data.rs: Parse 10-byte WEAP DATA (value + weight + damage). weapon_dnam.rs: Parse WEAP DNAM prefix (anim_type + speed + reach). WeaponAnimType enum maps u8 wire values (0-9) to animation types (HandToHandMelee...Crossbow). Both parsers tested.
WeaponRecord now exposes animation_type, speed, reach, value, weight, damage, enchantment (resolved FormId), template_weapon (resolved FormId) in addition to the existing editor_id + keywords. Existing integration tests still pass since all new fields default to None when the corresponding subrecords aren't present.
ArmorData { value, weight } (8 bytes). ArmorDnam { armor_rating }
decodes from the i32-stored-as-display-times-100 format into a
display-scale f32. BipedObject { slots_bitmask, armor_type }
parses BOD2 (8 bytes, SSE primary) or BODT (12 bytes, legacy);
slot_numbers() decodes the bitmask into slot numbers 30..=61.
ArmorType enum for LightArmor/HeavyArmor/Clothing.
9 unit tests covering DATA layout, DNAM display-scaling,
BOD2 parsing, BODT padding-skip, multi-slot decode, unknown
armor type.
ArmorRecord gains armor_type, body_slots (Vec<u8> of slot numbers), armor_rating, value, weight, enchantment, template_armor. BOD2 is preferred over BODT when both are present (SSE should not have both; defensive against old LE plugins). TNAM (not CNAM — ARMO uses a different signature than WEAP) carries the template armor reference.
Maps WeaponTraits fields against WeaponRecord subrecord data. - anim_types: OR — at least one must match - require_enchanted / require_template: Some(true/false) enforces presence / absence of EITM / CNAM - damage_range / weight_range: inclusive; records without DATA fail the predicate (matches KID's 'no data to check = fails filter')
Maps ArmorTraits fields against ArmorRecord subrecord data. - armor_types: OR across Heavy/Light/Clothing - require_enchanted / require_template: EITM / TNAM presence - ar_range / weight_range: inclusive; missing data fails predicate - body_slots: OR; at least one listed slot must be occupied
Previous Plan 6 implementation log-and-skipped trait predicates because WeaponRecord/ArmorRecord didn't expose the required subrecord fields. Now that mora-esp parses DATA/DNAM/EITM/CNAM/ TNAM/BOD2/BODT, wire the filter::evaluate_weapon_traits and evaluate_armor_traits calls into both the WEAP and ARMO loops. Trait-mismatch items increment rejected_by_filter.
6 end-to-end tests against synthetic plugins: weapon_animation_type_filter, weapon_damage_range_filter, weapon_enchanted_predicate, armor_type_filter, armor_body_slot_filter, armor_ar_range_filter. Exercises the full Plan 8b pipeline: mora-esp parses the new subrecords, mora-kid's evaluate_*_traits helpers gate emissions. Note: plan listed the INI trait field as field index 3 (|||traits) but the actual format is field index 2 (||traits); corrected here.
Clippy collapsed two nested if-lets in filter.rs via autofix. Fmt normalized whitespace. No functional changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Plan 8b of the Rust + KID pivot: activate KID trait predicate evaluation for Weapon and Armor records. Previously the distributor logged-and-skipped any rule with traits; it now evaluates them against fully-parsed record data.
WeaponRecordwith DATA (value/weight/damage), DNAM (animation_type, speed, reach), EITM (enchantment), CNAM (template weapon); extendedArmorRecordwith DATA (armor_rating × 100, value, weight), DNAM (armor_type), BOD2/BODT (body_slots), EITM (enchantment), TNAM (template armor — note: TNAM, not CNAM like WEAP).filter::evaluate_weapon_traits+evaluate_armor_traits; distributor now calls them instead of log-and-skip.trait_predicates.rsintegration tests covering each new predicate bucket.Total suite now at 206 tests (up from 181).
Scope
Plan 8b intentionally covers WEAP + ARMO only. The other 17 KID-supported record types remain log-and-skip for now; each will get its own plan once we have a real-game golden-test baseline (M4).
Test plan
cargo test --workspace→ 206/206cargo clippy --workspace --all-targets -- -D warningscargo fmt --checkcargo xwin check --target x86_64-pc-windows-msvc --workspace