Player attributes decoding is complete and fully working

This commit is contained in:
mykola2312 2023-09-08 23:28:58 +03:00
parent 33e9cdaa75
commit 33b1915b83
3 changed files with 199 additions and 41 deletions

View file

@ -1,8 +1,8 @@
use super::esh::{ESHValue, ESH};
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use super::esh::{ESH, ESHValue};
use super::tag::Tag; use super::tag::Tag;
use anyhow::{anyhow, Result};
use indexmap::IndexMap; use indexmap::IndexMap;
use anyhow::{Result, anyhow};
const STATS: [&str; 7] = [ const STATS: [&str; 7] = [
"strength", "strength",
@ -11,7 +11,7 @@ const STATS: [&str; 7] = [
"charisma", "charisma",
"intelligence", "intelligence",
"agility", "agility",
"luck" "luck",
]; ];
const TRAITS: [&str; 11] = [ const TRAITS: [&str; 11] = [
@ -25,7 +25,7 @@ const TRAITS: [&str; 11] = [
"age", "age",
"bonusAC", "bonusAC",
"sex", "sex",
"race" "race",
]; ];
const DERIVED: [&str; 26] = [ const DERIVED: [&str; 26] = [
@ -54,7 +54,7 @@ const DERIVED: [&str; 26] = [
"meleeDamage", "meleeDamage",
"bonusDamage", "bonusDamage",
"skillPerLevel", "skillPerLevel",
"levelsPerPerk" "levelsPerPerk",
]; ];
const SKILLS: [&str; 18] = [ const SKILLS: [&str; 18] = [
@ -75,7 +75,7 @@ const SKILLS: [&str; 18] = [
"pilot", "pilot",
"barter", "barter",
"gambling", "gambling",
"outdoorsman" "outdoorsman",
]; ];
const OPT_TRAITS: [&str; 38] = [ const OPT_TRAITS: [&str; 38] = [
@ -116,10 +116,138 @@ const OPT_TRAITS: [&str; 38] = [
"doDieHard", "doDieHard",
"doHthEvade", "doHthEvade",
"doDrunkenMaster", "doDrunkenMaster",
"doNightPerson" "doNightPerson",
]; ];
pub struct Attributes { const PERKS: [&str; 111] = [
"awareness",
"bonusHtHAttacks",
"bonusHtHDamage",
"bonusMove",
"bonusRangedDamage",
"bonusRateofFire",
"fasterHealing",
"moreCriticals",
"nightVision",
"radResistance",
"toughness",
"strongBack",
"sharpshooter",
"silentRunning",
"survivalist",
"masterTrader",
"educated",
"healer",
"fortuneFinder",
"betterCriticals",
"slayer",
"sniper",
"silentDeath",
"actionBoy",
"lifegiver",
"dodger",
"snakeater",
"mrFixit",
"medic",
"masterThief",
"heaveHo",
"pickpocket",
"ghost",
"explorer",
"flowerChild",
"pathfinder",
"scout",
"mysteriousStranger",
"ranger",
"quickPockets",
"swiftLearner",
"tag",
"mutate",
"adrenalineRush",
"cautiousNature",
"comprehension",
"demolitionExpert",
"gambler",
"gainStrenght",
"gainPerception",
"gainEndurance",
"gainCharisma",
"gainIntelligence",
"gainAgility",
"gainLuck",
"harmless",
"hereandNow",
"hthEvade",
"lightStep",
"livingAnatomy",
"negotiator",
"packRat",
"pyromaniac",
"quickRecovery",
"salesman",
"stonewall",
"thief",
"weaponHandling",
"stuntMan",
"crazyBomber",
"roadWarrior",
"gunner",
"leadFoot",
"tunnelRat",
"bracing",
"flexible",
"bendTheRules",
"breakTheRules",
"loner",
"teamPlayer",
"leader",
"hitTheDeck",
"boneHead",
"brownNoser",
"dieHard",
"drunkenMaster",
"stat",
"radChild",
"cancerousGrowth",
"bonsai",
"steadyArm",
"psychotic",
"toughHige",
"deathSense",
"brutishHulk",
"talonOfFear",
"hideOfScars",
"wayOfTheFruit",
"twitchGamer",
"bluffMaster",
"divineFavour",
"unk1",
"unk2",
"unk3",
"unk4",
"unk5",
"unk6",
"unk7",
"unk8",
"unk9",
"unk10",
];
const ADDICTIONS: [&str; 10] = [
"buffoutAddiction",
"afterburnerAddiction",
"mentatsAddiction",
"psychoAddiction",
"radAwayAddiction",
"voodooAddiction",
"nukaColaAddiction",
"boozeAddiction",
"withdrawal",
"drunk",
];
#[derive(Debug)]
pub struct Attributes {
esh: ESH, esh: ESH,
pub stats: IndexMap<&'static str, u32>, pub stats: IndexMap<&'static str, u32>,
pub traits: IndexMap<&'static str, u32>, pub traits: IndexMap<&'static str, u32>,
@ -128,11 +256,11 @@ pub struct Attributes {
pub skill_tags: IndexMap<&'static str, bool>, pub skill_tags: IndexMap<&'static str, bool>,
pub opt_traits: IndexMap<&'static str, bool>, pub opt_traits: IndexMap<&'static str, bool>,
pub perks: IndexMap<&'static str, u32>, pub perks: IndexMap<&'static str, u32>,
pub addictions: IndexMap<&'static str, u32> pub addictions: IndexMap<&'static str, u32>,
} }
impl Attributes { impl Attributes {
fn from_binary(bin: &[u8]) -> Result<Self> { pub fn from_binary(bin: &[u8]) -> Result<Self> {
let mut rd = ReadStream::new(bin, 0); let mut rd = ReadStream::new(bin, 0);
let _ = rd.read_u32()?; let _ = rd.read_u32()?;
@ -141,24 +269,59 @@ impl Attributes {
return Err(anyhow!("Attributes Binary == false")); return Err(anyhow!("Attributes Binary == false"));
} }
let mut stats: IndexMap<&'static str, u32>; let mut stats: IndexMap<&'static str, u32> = IndexMap::with_capacity(7);
let mut traits: IndexMap<&'static str, u32>; let mut traits: IndexMap<&'static str, u32> = IndexMap::with_capacity(11);
let mut derived: IndexMap<&'static str, u32>; let mut derived: IndexMap<&'static str, u32> = IndexMap::with_capacity(26);
let mut skills: IndexMap<&'static str, u32>; let mut skills: IndexMap<&'static str, u32> = IndexMap::with_capacity(18);
let mut skill_tags: IndexMap<&'static str, bool>; let mut skill_tags: IndexMap<&'static str, bool> = IndexMap::with_capacity(18);
let mut opt_traits: IndexMap<&'static str, bool>; let mut opt_traits: IndexMap<&'static str, bool> = IndexMap::with_capacity(38);
let mut perks: IndexMap<&'static str, u32>; let mut perks: IndexMap<&'static str, u32> = IndexMap::with_capacity(111);
let mut addictions: IndexMap<&'static str, u32>; let mut addictions: IndexMap<&'static str, u32> = IndexMap::with_capacity(10);
if let ESHValue::Binary(binary) = &esh.props["esbin"] { if let ESHValue::Binary(binary) = &esh.props["esbin"] {
let mut rd = ReadStream::new(&binary, 0); let mut rd = ReadStream::new(&binary, 0);
let _ = rd.read_u32()?; let _ = rd.read_u32()?;
let _: Tag = rd.read()?; let _: Tag = rd.read()?;
for i in 0..7 {
stats.insert(STATS[i], rd.read_u32()?);
}
for i in 0..11 {
traits.insert(TRAITS[i], rd.read_u32()?);
}
for i in 0..26 {
derived.insert(DERIVED[i], rd.read_u32()?);
}
for i in 0..18 {
skills.insert(SKILLS[i], rd.read_u32()?);
}
for i in 0..18 {
skill_tags.insert(SKILLS[i], rd.read_bool()?);
}
for i in 0..38 {
opt_traits.insert(OPT_TRAITS[i], rd.read_bool()?);
}
for i in 0..111 {
perks.insert(PERKS[i], rd.read_u32()?);
}
for i in 0..10 {
addictions.insert(ADDICTIONS[i], rd.read_u32()?);
}
Ok(Attributes {
esh,
stats,
traits,
derived,
skills,
skill_tags,
opt_traits,
perks,
addictions,
})
} else { } else {
return Err(anyhow!("Attributes has no esbin")); return Err(anyhow!("Attributes has no esbin"));
} }
todo!()
} }
} }

View file

@ -70,6 +70,10 @@ impl<'a> ReadStream<'a> {
Ok(self.rdr.read_u8()?) Ok(self.rdr.read_u8()?)
} }
pub fn read_bool(&mut self) -> Result<bool> {
Ok(self.read_u8()? != 0)
}
pub fn read_u16(&mut self) -> Result<u16> { pub fn read_u16(&mut self) -> Result<u16> {
Ok(self.rdr.read_u16::<LittleEndian>()?) Ok(self.rdr.read_u16::<LittleEndian>()?)
} }
@ -148,6 +152,10 @@ impl WriteStream {
Ok(self.buf.write_u8(val)?) Ok(self.buf.write_u8(val)?)
} }
pub fn write_bool(&mut self, val: bool) -> Result<()> {
self.write_u8(val as u8)
}
pub fn write_u16(&mut self, val: u16) -> Result<()> { pub fn write_u16(&mut self, val: u16) -> Result<()> {
Ok(self.buf.write_u16::<LittleEndian>(val)?) Ok(self.buf.write_u16::<LittleEndian>(val)?)
} }

View file

@ -1,3 +1,5 @@
use crate::fot::attributes;
use super::decoder::DecoderCtx; use super::decoder::DecoderCtx;
use super::entitylist::{EntityEncoding, EntityList}; use super::entitylist::{EntityEncoding, EntityList};
use super::fstring::FString; use super::fstring::FString;
@ -12,6 +14,7 @@ use deflate::deflate_bytes_zlib;
use inflate::inflate_bytes_zlib; use inflate::inflate_bytes_zlib;
use super::esh::{ESHValue, ESH}; use super::esh::{ESHValue, ESH};
use super::attributes::Attributes;
use std::path::Path; use std::path::Path;
pub struct World { pub struct World {
@ -43,25 +46,9 @@ impl World {
//self.entlist.dump_to_entfile(ent, Path::new("D:\\actor.ent"))?; //self.entlist.dump_to_entfile(ent, Path::new("D:\\actor.ent"))?;
println!(""); println!("");
if let ESHValue::Binary(attributes) = &esh.props["Attributes"] { if let ESHValue::Binary(binary) = &esh.props["Attributes"] {
let mut rd = ReadStream::new(&attributes, 0); let attributes = Attributes::from_binary(&binary)?;
dbg!(attributes);
let size = rd.read_u32()?;
let attrs_esh: ESH = rd.read()?;
for (name, value) in &attrs_esh.props {
println!("{} {}", name, value);
}
}
println!("");
if let ESHValue::Binary(attributes) = &esh.props["Modifiers"] {
let mut rd = ReadStream::new(&attributes, 0);
let size = rd.read_u32()?;
let attrs_esh: ESH = rd.read()?;
for (name, value) in &attrs_esh.props {
println!("{} {}", name, value);
}
} }
Ok(()) Ok(())