Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/esp/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,5 @@ make_delegate!(
SoundGen
Dialogue
DialogueInfo
ScriptConfigList
);
6 changes: 6 additions & 0 deletions libs/esp/src/traits/editor_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ impl EditorId for Header {
}
}

impl EditorId for ScriptConfigList {
fn editor_id(&self) -> Cow<'_, str> {
"".into()
}
}

impl EditorId for Skill {
fn editor_id(&self) -> Cow<'_, str> {
self.skill_id.display().into()
Expand Down
1 change: 1 addition & 0 deletions libs/esp/src/traits/sort_objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl Plugin {
TES3Object::SoundGen(obj) => (38, obj.sort_hint(), &*obj.id),
TES3Object::Dialogue(obj) => (39, obj.sort_hint(), ""), // Preserve DIAL/INFO order
TES3Object::DialogueInfo(obj) => (39, obj.sort_hint(), ""), // ^
TES3Object::ScriptConfigList(obj) => (40, obj.sort_hint(), ""),
}
});
unsafe { apply_isort(&mut indices, &mut self.objects) };
Expand Down
3 changes: 3 additions & 0 deletions libs/esp/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod lockpick;
mod magiceffect;
mod miscitem;
mod npc;
mod omw_lualist;
mod pathgrid;
mod plugin;
mod probe;
Expand Down Expand Up @@ -89,6 +90,7 @@ pub use lockpick::*;
pub use magiceffect::*;
pub use miscitem::*;
pub use npc::*;
pub use omw_lualist::*;
pub use pathgrid::*;
pub use plugin::*;
pub use probe::*;
Expand Down Expand Up @@ -153,4 +155,5 @@ pub enum TES3Object {
#[tag("PGRD")] PathGrid(PathGrid),
#[tag("DIAL")] Dialogue(Dialogue),
#[tag("INFO")] DialogueInfo(DialogueInfo),
#[tag("LUAL")] ScriptConfigList(ScriptConfigList)
}
13 changes: 13 additions & 0 deletions libs/esp/src/types/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,16 @@ bitflags! {
const NOT_PLAYABLE = 0x2;
}
}

bitflags! {
#[esp_meta]
#[repr(transparent)]
#[derive(LoadSave, Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct OMWScriptAttachFlag: u32 {
const GLOBAL = 0x01;
const CUSTOM = 0x02;
const PLAYER = 0x04;
const MERGE = 0x08;
const MENU = 0x10;
}
}
189 changes: 189 additions & 0 deletions libs/esp/src/types/omw_lualist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// internal imports
use crate::prelude::*;

#[esp_meta]
#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct PerInstanceConfig {
pub attach: bool,
pub mast_idx: i32,
pub ref_idx: u32,
pub data: Vec<u8>,
}

#[esp_meta]
#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct PerRecordConfig {
pub attach: bool,
pub id: String,
pub data: Vec<u8>,
}

#[esp_meta]
#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct ScriptConfig {
pub path: String,
pub init_data: Vec<u8>, // We'll need to reimplement openmw's serializer too :/
pub flags: OMWScriptAttachFlag,
pub types: Vec<String>,
pub records: Vec<PerRecordConfig>,
pub instances: Vec<PerInstanceConfig>,
}

#[esp_meta]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ScriptConfigList {
pub scripts: Vec<ScriptConfig>,
pub flags: ObjectFlags,
}

impl Load for ScriptConfigList {
fn load(stream: &mut Reader<'_>) -> io::Result<Self> {
let mut this: Self = default();
let mut script_config: ScriptConfig = ScriptConfig::default();

this.flags = stream.load()?;

let mut last_tag: Option<[u8; 4]> = None;
while let Ok(tag) = stream.load() {
match &tag {
b"LUAS" => {
if script_config != ScriptConfig::default() {
this.scripts.push(std::mem::take(&mut script_config));
}

script_config.path = stream.load()?;
}
b"LUAF" => {
let size: u32 = stream.load()?;
assert!(size % 4 == 0, "Incorrect LUAF Size!");

script_config.flags = stream.load()?;

for _ in 0..(size / 4 - 1) {
let type_string: String = stream.load_string(4)?;
script_config.types.push(type_string);
}
}
b"LUAI" => {
let mut per_instance = PerInstanceConfig::default();
stream.skip(size_of::<u32>() as u32)?;

let attach = stream.load::<u8>()?;
per_instance.attach = attach != 0;

per_instance.ref_idx = stream.load()?;
per_instance.mast_idx = stream.load()?;

script_config.instances.push(per_instance);
}
b"LUAR" => {
let mut per_record = PerRecordConfig::default();
let size: u32 = stream.load()?;

let attach = stream.load::<u8>()?;
per_record.attach = attach != 0;

per_record.id = stream.load_string(size as usize - 1)?;

script_config.records.push(per_record);
}
b"LUAD" => {
let size: u32 = stream.load()?;
let data: Vec<u8> = stream.load_seq(size)?;

if let Some(tag) = &last_tag {
match tag {
b"LUAF" => script_config.init_data = data,
b"LUAI" => {
let last_instance = script_config
.instances
.last_mut()
.expect("No instance found in scriptConfig!");
last_instance.data = data;
}
b"LUAR" => {
script_config
.records
.last_mut()
.expect("No record found in scriptConfig!")
.data = data
}
_ => {
Reader::error(format!(
"Unexpected Data Tag Preceding LUAD: {}::{}",
this.tag_str(),
tag.to_str_lossy()
))?;
}
}
}
}
_ => {
Reader::error(format!("Unexpected Tag: {}::{}", this.tag_str(), tag.to_str_lossy()))?;
}
}

last_tag = Some(tag);
}

if script_config != ScriptConfig::default() {
this.scripts.push(std::mem::take(&mut script_config))
}

Ok(this)
}
}

impl Save for ScriptConfigList {
fn save(&self, stream: &mut Writer) -> io::Result<()> {
stream.save(&self.flags)?;
for script_config in &self.scripts {
stream.save(b"LUAS")?;
stream.save_string_without_null_terminator(&script_config.path)?;

stream.save(b"LUAF")?;
let length = 4 + (4 * script_config.types.len());
stream.save(&(length as u32))?;
stream.save(&script_config.flags)?;

for attach_type in &script_config.types {
stream.save_vec(attach_type.as_bytes().into())?;
}

if script_config.init_data.len() > 0 {
stream.save(b"LUAD")?;
stream.save(&script_config.init_data)?;
}

for record in &script_config.records {
stream.save(b"LUAR")?;
let length = record.id.len() as u32;
stream.save(&(length + 1))?;
stream.save_as::<u8>(record.attach)?;
stream.save_bytes(&record.id[..].as_bytes())?;

if record.data.len() > 0 {
stream.save(b"LUAD")?;
stream.save(&record.data)?;
}
}

for instance in &script_config.instances {
stream.save(b"LUAI")?;

stream.save(&9)?;
stream.save_as::<u8>(instance.attach)?;

stream.save(&instance.ref_idx)?;
stream.save(&instance.mast_idx)?;

if instance.data.len() > 0 {
stream.save(b"LUAD")?;
stream.save(&instance.data)?;
}
}
}

Ok(())
}
}