use std::fmt::Debug;
use std::hash::Hash;
use std::mem::size_of;
use byteorder::LE;
use enum_dispatch::enum_dispatch;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use ordered_float::OrderedFloat;
use unreal_asset_proc_macro::FNameContainer;
use crate::error::KismetError;
use crate::object_version::{ObjectVersion, ObjectVersionUE5};
use crate::reader::{archive_reader::ArchiveReader, archive_writer::ArchiveWriter};
use crate::types::vector::{Transform, Vector, Vector4};
use crate::types::{fname::FName, PackageIndex};
use crate::Error;
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum EExprToken {
ExLocalVariable = 0x00,
ExInstanceVariable = 0x01,
ExDefaultVariable = 0x02,
ExReturn = 0x04,
ExJump = 0x06,
ExJumpIfNot = 0x07,
ExAssert = 0x09,
ExNothing = 0x0B,
ExLet = 0x0F,
ExClassContext = 0x12,
ExMetaCast = 0x13,
ExLetBool = 0x14,
ExEndParmValue = 0x15,
ExEndFunctionParms = 0x16,
ExSelf = 0x17,
ExSkip = 0x18,
ExContext = 0x19,
ExContextFailSilent = 0x1A,
ExVirtualFunction = 0x1B,
ExFinalFunction = 0x1C,
ExIntConst = 0x1D,
ExFloatConst = 0x1E,
ExStringConst = 0x1F,
ExObjectConst = 0x20,
ExNameConst = 0x21,
ExRotationConst = 0x22,
ExVectorConst = 0x23,
ExByteConst = 0x24,
ExIntZero = 0x25,
ExIntOne = 0x26,
ExTrue = 0x27,
ExFalse = 0x28,
ExTextConst = 0x29,
ExNoObject = 0x2A,
ExTransformConst = 0x2B,
ExIntConstByte = 0x2C,
ExNoInterface = 0x2D,
ExDynamicCast = 0x2E,
ExStructConst = 0x2F,
ExEndStructConst = 0x30,
ExSetArray = 0x31,
ExEndArray = 0x32,
ExPropertyConst = 0x33,
ExUnicodeStringConst = 0x34,
ExInt64Const = 0x35,
ExUInt64Const = 0x36,
ExPrimitiveCast = 0x38,
ExSetSet = 0x39,
ExEndSet = 0x3A,
ExSetMap = 0x3B,
ExEndMap = 0x3C,
ExSetConst = 0x3D,
ExEndSetConst = 0x3E,
ExMapConst = 0x3F,
ExEndMapConst = 0x40,
ExStructMemberContext = 0x42,
ExLetMulticastDelegate = 0x43,
ExLetDelegate = 0x44,
ExLocalVirtualFunction = 0x45,
ExLocalFinalFunction = 0x46,
ExLocalOutVariable = 0x48,
ExDeprecatedOp4A = 0x4A,
ExInstanceDelegate = 0x4B,
ExPushExecutionFlow = 0x4C,
ExPopExecutionFlow = 0x4D,
ExComputedJump = 0x4E,
ExPopExecutionFlowIfNot = 0x4F,
ExBreakpoint = 0x50,
ExInterfaceContext = 0x51,
ExObjToInterfaceCast = 0x52,
ExEndOfScript = 0x53,
ExCrossInterfaceCast = 0x54,
ExInterfaceToObjCast = 0x55,
ExWireTracepoint = 0x5A,
ExSkipOffsetConst = 0x5B,
ExAddMulticastDelegate = 0x5C,
ExClearMulticastDelegate = 0x5D,
ExTracepoint = 0x5E,
ExLetObj = 0x5F,
ExLetWeakObjPtr = 0x60,
ExBindDelegate = 0x61,
ExRemoveMulticastDelegate = 0x62,
ExCallMulticastDelegate = 0x63,
ExLetValueOnPersistentFrame = 0x64,
ExArrayConst = 0x65,
ExEndArrayConst = 0x66,
ExSoftObjectConst = 0x67,
ExCallMath = 0x68,
ExSwitchValue = 0x69,
ExInstrumentationEvent = 0x6A,
ExArrayGetByRef = 0x6B,
ExClassSparseDataVariable = 0x6C,
ExFieldPathConst = 0x6D,
ExMax = 0xff,
}
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum ECastToken {
ObjectToInterface = 0x46,
ObjectToBool = 0x47,
InterfaceToBool = 0x49,
Max = 0xFF,
}
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum EScriptInstrumentationType {
Class = 0,
ClassScope,
Instance,
Event,
InlineEvent,
ResumeEvent,
PureNodeEntry,
NodeDebugSite,
NodeEntry,
NodeExit,
PushState,
RestoreState,
ResetState,
SuspendState,
PopState,
TunnelEndOfThread,
Stop,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum EBlueprintTextLiteralType {
Empty,
LocalizedText,
InvariantText,
LiteralString,
StringTableEntry,
}
#[derive(FNameContainer, Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct FieldPath {
pub path: Vec<FName>,
#[container_ignore]
pub resolved_owner: PackageIndex,
}
impl FieldPath {
pub fn new(path: Vec<FName>, resolved_owner: PackageIndex) -> Self {
FieldPath {
path,
resolved_owner,
}
}
}
fn read_kismet_string<Reader: ArchiveReader>(asset: &mut Reader) -> Result<String, Error> {
let mut data = Vec::new();
loop {
let read = asset.read_u8()?;
if read == 0 {
break;
}
data.push(read);
}
Ok(String::from_utf8(data)?)
}
fn read_kismet_unicode_string<Reader: ArchiveReader>(asset: &mut Reader) -> Result<String, Error> {
let mut data = Vec::new();
loop {
let b1 = asset.read_u8()?;
let b2 = asset.read_u8()?;
if b1 == 0 && b2 == 0 {
break;
}
data.push(((b2 as u16) << 8) | b1 as u16)
}
Ok(String::from_utf16(&data)?)
}
fn write_kismet_string<Writer: ArchiveWriter>(
string: &str,
asset: &mut Writer,
) -> Result<usize, Error> {
let begin = asset.position();
asset.write_all(string.as_bytes())?;
asset.write_all(&[0u8; 1])?;
Ok((asset.position() - begin) as usize)
}
fn write_kismet_unicode_string<Writer: ArchiveWriter>(
string: &str,
asset: &mut Writer,
) -> Result<usize, Error> {
let begin = asset.position();
let utf16 = string.encode_utf16().collect::<Vec<_>>();
let (_, aligned, _) = unsafe { utf16.align_to::<u8>() };
asset.write_all(aligned)?;
asset.write_all(&[0u8; 2])?;
Ok((asset.position() - begin) as usize)
}
macro_rules! declare_expression {
(
$name:ident,
$(
$(#[$inner:ident $($args:tt)*])*
$v:ident: $t:ty
),*
) => {
#[derive(FNameContainer, Debug, Clone, PartialEq, Eq, Hash)]
pub struct $name {
#[container_ignore]
pub token: EExprToken,
$(
$(#[$inner $($args)*])*
pub $v: $t,
)*
}
impl KismetExpressionEnumEqTrait for $name {
fn enum_eq(&self, token: &EExprToken) -> bool { self.token == *token }
}
impl KismetExpressionDataTrait for $name {
fn get_token(&self) -> EExprToken { self.token }
}
}
}
macro_rules! implement_expression {
(
$(
$(#[$inner:ident $($args:tt)*])*
$name:ident
),*
) => {
$(
$(#[$inner $($args)*])*
#[derive(FNameContainer, Debug, Clone, PartialEq, Eq, Hash)]
pub struct $name {
#[container_ignore]
pub token: EExprToken
}
impl KismetExpressionTrait for $name {
fn write<Writer: ArchiveWriter>(&self, _asset: &mut Writer) -> Result<usize, Error> {
Ok(0)
}
}
impl KismetExpressionEnumEqTrait for $name {
fn enum_eq(&self, token: &EExprToken) -> bool { self.token == *token }
}
impl KismetExpressionDataTrait for $name {
fn get_token(&self) -> EExprToken { self.token }
}
impl $name {
pub fn new<Reader: ArchiveReader>(_asset: &mut Reader) -> Result<Self, Error> {
Ok($name {
token: EExprToken::$name
})
}
}
impl Default for $name {
fn default() -> Self {
$name { token: EExprToken::$name }
}
}
)*
}
}
macro_rules! implement_value_expression {
($name:ident, $param:ty, $read_func:ident, $write_func:ident) => {
declare_expression!(
$name,
value: $param
);
impl $name {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok($name {
token: EExprToken::$name,
value: asset.$read_func()?,
})
}
}
impl KismetExpressionTrait for $name {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.$write_func(self.value)?;
Ok(size_of::<$param>())
}
}
};
($name:ident, $param:ty, $read_func:ident, $write_func:ident, $endianness:ident) => {
declare_expression!(
$name,
value: $param
);
impl $name {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok($name {
token: EExprToken::$name,
value: asset.$read_func::<$endianness>()?,
})
}
}
impl KismetExpressionTrait for $name {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.$write_func::<$endianness>(self.value)?;
Ok(size_of::<$param>())
}
}
};
}
#[derive(FNameContainer, Debug, Clone, PartialEq, Eq, Hash)]
pub struct FScriptText {
#[container_ignore]
text_literal_type: EBlueprintTextLiteralType,
localized_source: Option<KismetExpression>,
localized_key: Option<KismetExpression>,
localized_namespace: Option<KismetExpression>,
invariant_literal_string: Option<KismetExpression>,
literal_string: Option<KismetExpression>,
#[container_ignore]
string_table_asset: Option<PackageIndex>,
string_table_id: Option<KismetExpression>,
string_table_key: Option<KismetExpression>,
}
impl FScriptText {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let text_literal_type: EBlueprintTextLiteralType = asset.read_u8()?.try_into()?;
let (
mut localized_source,
mut localized_key,
mut localized_namespace,
mut invariant_literal_string,
mut literal_string,
mut string_table_asset,
mut string_table_id,
mut string_table_key,
) = (None, None, None, None, None, None, None, None);
match text_literal_type {
EBlueprintTextLiteralType::LocalizedText => {
localized_source = Some(KismetExpression::new(asset)?);
localized_key = Some(KismetExpression::new(asset)?);
localized_namespace = Some(KismetExpression::new(asset)?);
}
EBlueprintTextLiteralType::InvariantText => {
invariant_literal_string = Some(KismetExpression::new(asset)?);
}
EBlueprintTextLiteralType::LiteralString => {
literal_string = Some(KismetExpression::new(asset)?);
}
EBlueprintTextLiteralType::StringTableEntry => {
string_table_asset = Some(PackageIndex::new(asset.read_i32::<LE>()?));
string_table_id = Some(KismetExpression::new(asset)?);
string_table_key = Some(KismetExpression::new(asset)?);
}
_ => {}
};
Ok(FScriptText {
text_literal_type,
localized_source,
localized_key,
localized_namespace,
invariant_literal_string,
literal_string,
string_table_asset,
string_table_id,
string_table_key,
})
}
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u8>();
asset.write_u8(self.text_literal_type.into())?;
match self.text_literal_type {
EBlueprintTextLiteralType::Empty => {}
EBlueprintTextLiteralType::LocalizedText => {
offset += KismetExpression::write(
self.localized_source.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is LocalizedText but localized_source is None"
.to_string(),
)
})?,
asset,
)?;
offset += KismetExpression::write(
self.localized_key.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is LocalizedText but localized_key is None"
.to_string(),
)
})?,
asset,
)?;
offset += KismetExpression::write(
self.localized_namespace.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is LocalizedText but localized_namespace is None"
.to_string(),
)
})?,
asset,
)?;
}
EBlueprintTextLiteralType::InvariantText => {
offset += KismetExpression::write(
self.invariant_literal_string.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is InvariantText but invariant_literal_string is None"
.to_string(),
)
})?,
asset,
)?;
}
EBlueprintTextLiteralType::LiteralString => {
offset += KismetExpression::write(
self.literal_string.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is LiteralString but literal_string is None"
.to_string(),
)
})?,
asset,
)?;
}
EBlueprintTextLiteralType::StringTableEntry => {
asset.write_i32::<LE>(self.string_table_asset.map(|e| e.index).ok_or_else(
|| {
Error::no_data(
"text_literal_type is StringTableEntry but string_table_asset is None"
.to_string(),
)
},
)?)?;
offset += size_of::<u64>();
offset += KismetExpression::write(
self.string_table_id.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is StringTalbleEntry but string_table_id is None"
.to_string(),
)
})?,
asset,
)?;
offset += KismetExpression::write(
self.string_table_key.as_ref().ok_or_else(|| {
Error::no_data(
"text_literal_type is StringTableEntry but string_table_key is None"
.to_string(),
)
})?,
asset,
)?;
}
}
Ok(offset)
}
}
#[derive(FNameContainer, Debug, Default, Clone, PartialEq, Eq, Hash)]
pub struct KismetPropertyPointer {
#[container_ignore]
pub old: Option<PackageIndex>,
pub new: Option<FieldPath>,
}
impl KismetPropertyPointer {
const XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION: ObjectVersion =
ObjectVersion::VER_UE4_ADDED_PACKAGE_OWNER;
pub fn from_old(old: PackageIndex) -> Self {
KismetPropertyPointer {
old: Some(old),
new: None,
}
}
pub fn from_new(new: FieldPath) -> Self {
KismetPropertyPointer {
old: None,
new: Some(new),
}
}
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
if asset.get_object_version()
>= KismetPropertyPointer::XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION
{
let num_entries = asset.read_i32::<LE>()?;
let mut names = Vec::with_capacity(num_entries as usize);
for _i in 0..num_entries as usize {
names.push(asset.read_fname()?);
}
let owner = PackageIndex::new(asset.read_i32::<LE>()?);
Ok(KismetPropertyPointer::from_new(FieldPath::new(
names, owner,
)))
} else {
Ok(KismetPropertyPointer::from_old(PackageIndex::new(
asset.read_i32::<LE>()?,
)))
}
}
pub fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
if asset.get_object_version()
>= KismetPropertyPointer::XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION
{
let new = self.new.as_ref().ok_or_else(|| {
Error::no_data(
"engine_version >= UE4_ADDED_PACKAGE_OWNER but new is None".to_string(),
)
})?;
asset.write_i32::<LE>(new.path.len() as i32)?;
for entry in &new.path {
asset.write_fname(entry)?;
}
asset.write_i32::<LE>(new.resolved_owner.index)?;
} else {
asset.write_i32::<LE>(self.old.map(|e| e.index).ok_or_else(|| {
Error::no_data(
"engine_version < UE4_ADDED_PAFCKAGE_OWNER but old is None".to_string(),
)
})?)?;
}
Ok(size_of::<u64>())
}
}
#[derive(FNameContainer, Debug, Clone, PartialEq, Eq, Hash)]
pub struct KismetSwitchCase {
pub case_index_value_term: KismetExpression,
pub next_offset: u32,
pub case_term: KismetExpression,
}
impl KismetSwitchCase {
pub fn new(
case_index_value_term: KismetExpression,
next_offset: u32,
case_term: KismetExpression,
) -> Self {
KismetSwitchCase {
case_index_value_term,
next_offset,
case_term,
}
}
}
#[enum_dispatch]
pub trait KismetExpressionTrait: Debug + Clone + PartialEq + Eq + Hash {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error>;
}
#[enum_dispatch]
pub trait KismetExpressionDataTrait {
fn get_token(&self) -> EExprToken;
}
#[enum_dispatch]
pub trait KismetExpressionEnumEqTrait {
fn enum_eq(&self, token: &EExprToken) -> bool;
}
#[enum_dispatch(
KismetExpressionTrait,
KismetExpressionEnumEqTrait,
KismetExpressionDataTrait
)]
#[derive(FNameContainer, Debug, Clone, PartialEq, Hash)]
#[container_nobounds]
pub enum KismetExpression {
ExLocalVariable,
ExInstanceVariable,
ExDefaultVariable,
ExReturn,
ExJump,
ExJumpIfNot,
ExAssert,
ExNothing,
ExLet,
ExClassContext,
ExMetaCast,
ExLetBool,
ExEndParmValue,
ExEndFunctionParms,
ExSelf,
ExSkip,
ExContext,
ExContextFailSilent,
ExVirtualFunction,
ExFinalFunction,
ExIntConst,
ExFloatConst,
ExStringConst,
ExObjectConst,
ExNameConst,
ExRotationConst,
ExVectorConst,
ExByteConst,
ExIntZero,
ExIntOne,
ExTrue,
ExFalse,
ExTextConst,
ExNoObject,
ExTransformConst,
ExIntConstByte,
ExNoInterface,
ExDynamicCast,
ExStructConst,
ExEndStructConst,
ExSetArray,
ExEndArray,
ExPropertyConst,
ExUnicodeStringConst,
ExInt64Const,
ExUInt64Const,
ExPrimitiveCast,
ExSetSet,
ExEndSet,
ExSetMap,
ExEndMap,
ExSetConst,
ExEndSetConst,
ExMapConst,
ExEndMapConst,
ExStructMemberContext,
ExLetMulticastDelegate,
ExLetDelegate,
ExLocalVirtualFunction,
ExLocalFinalFunction,
ExLocalOutVariable,
ExDeprecatedOp4A,
ExInstanceDelegate,
ExPushExecutionFlow,
ExPopExecutionFlow,
ExComputedJump,
ExPopExecutionFlowIfNot,
ExBreakpoint,
ExInterfaceContext,
ExObjToInterfaceCast,
ExEndOfScript,
ExCrossInterfaceCast,
ExInterfaceToObjCast,
ExWireTracepoint,
ExSkipOffsetConst,
ExAddMulticastDelegate,
ExClearMulticastDelegate,
ExTracepoint,
ExLetObj,
ExLetWeakObjPtr,
ExBindDelegate,
ExRemoveMulticastDelegate,
ExCallMulticastDelegate,
ExLetValueOnPersistentFrame,
ExArrayConst,
ExEndArrayConst,
ExSoftObjectConst,
ExCallMath,
ExSwitchValue,
ExInstrumentationEvent,
ExArrayGetByRef,
ExClassSparseDataVariable,
ExFieldPathConst,
}
impl Eq for KismetExpression {}
impl KismetExpression {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let token: EExprToken = asset.read_u8()?.try_into()?;
let expr: Result<Self, Error> = match token {
EExprToken::ExLocalVariable => Ok(ExLocalVariable::new(asset)?.into()),
EExprToken::ExInstanceVariable => Ok(ExInstanceVariable::new(asset)?.into()),
EExprToken::ExDefaultVariable => Ok(ExDefaultVariable::new(asset)?.into()),
EExprToken::ExReturn => Ok(ExReturn::new(asset)?.into()),
EExprToken::ExJump => Ok(ExJump::new(asset)?.into()),
EExprToken::ExJumpIfNot => Ok(ExJumpIfNot::new(asset)?.into()),
EExprToken::ExAssert => Ok(ExAssert::new(asset)?.into()),
EExprToken::ExNothing => Ok(ExNothing::new(asset)?.into()),
EExprToken::ExLet => Ok(ExLet::new(asset)?.into()),
EExprToken::ExClassContext => Ok(ExClassContext::new(asset)?.into()),
EExprToken::ExMetaCast => Ok(ExMetaCast::new(asset)?.into()),
EExprToken::ExLetBool => Ok(ExLetBool::new(asset)?.into()),
EExprToken::ExEndParmValue => Ok(ExEndParmValue::new(asset)?.into()),
EExprToken::ExEndFunctionParms => Ok(ExEndFunctionParms::new(asset)?.into()),
EExprToken::ExSelf => Ok(ExSelf::new(asset)?.into()),
EExprToken::ExSkip => Ok(ExSkip::new(asset)?.into()),
EExprToken::ExContext => Ok(ExContext::new(asset)?.into()),
EExprToken::ExContextFailSilent => Ok(ExContextFailSilent::new(asset)?.into()),
EExprToken::ExVirtualFunction => Ok(ExVirtualFunction::new(asset)?.into()),
EExprToken::ExFinalFunction => Ok(ExFinalFunction::new(asset)?.into()),
EExprToken::ExIntConst => Ok(ExIntConst::new(asset)?.into()),
EExprToken::ExFloatConst => Ok(ExFloatConst::new(asset)?.into()),
EExprToken::ExStringConst => Ok(ExStringConst::new(asset)?.into()),
EExprToken::ExObjectConst => Ok(ExObjectConst::new(asset)?.into()),
EExprToken::ExNameConst => Ok(ExNameConst::new(asset)?.into()),
EExprToken::ExRotationConst => Ok(ExRotationConst::new(asset)?.into()),
EExprToken::ExVectorConst => Ok(ExVectorConst::new(asset)?.into()),
EExprToken::ExByteConst => Ok(ExByteConst::new(asset)?.into()),
EExprToken::ExIntZero => Ok(ExIntZero::new(asset)?.into()),
EExprToken::ExIntOne => Ok(ExIntOne::new(asset)?.into()),
EExprToken::ExTrue => Ok(ExTrue::new(asset)?.into()),
EExprToken::ExFalse => Ok(ExFalse::new(asset)?.into()),
EExprToken::ExTextConst => Ok(ExTextConst::new(asset)?.into()),
EExprToken::ExNoObject => Ok(ExNoObject::new(asset)?.into()),
EExprToken::ExTransformConst => Ok(ExTransformConst::new(asset)?.into()),
EExprToken::ExIntConstByte => Ok(ExIntConstByte::new(asset)?.into()),
EExprToken::ExNoInterface => Ok(ExNoInterface::new(asset)?.into()),
EExprToken::ExDynamicCast => Ok(ExDynamicCast::new(asset)?.into()),
EExprToken::ExStructConst => Ok(ExStructConst::new(asset)?.into()),
EExprToken::ExEndStructConst => Ok(ExEndStructConst::new(asset)?.into()),
EExprToken::ExSetArray => Ok(ExSetArray::new(asset)?.into()),
EExprToken::ExEndArray => Ok(ExEndArray::new(asset)?.into()),
EExprToken::ExPropertyConst => Ok(ExPropertyConst::new(asset)?.into()),
EExprToken::ExUnicodeStringConst => Ok(ExUnicodeStringConst::new(asset)?.into()),
EExprToken::ExInt64Const => Ok(ExInt64Const::new(asset)?.into()),
EExprToken::ExUInt64Const => Ok(ExUInt64Const::new(asset)?.into()),
EExprToken::ExPrimitiveCast => Ok(ExPrimitiveCast::new(asset)?.into()),
EExprToken::ExSetSet => Ok(ExSetSet::new(asset)?.into()),
EExprToken::ExEndSet => Ok(ExEndSet::new(asset)?.into()),
EExprToken::ExSetMap => Ok(ExSetMap::new(asset)?.into()),
EExprToken::ExEndMap => Ok(ExEndMap::new(asset)?.into()),
EExprToken::ExSetConst => Ok(ExSetConst::new(asset)?.into()),
EExprToken::ExEndSetConst => Ok(ExEndSetConst::new(asset)?.into()),
EExprToken::ExMapConst => Ok(ExMapConst::new(asset)?.into()),
EExprToken::ExEndMapConst => Ok(ExEndMapConst::new(asset)?.into()),
EExprToken::ExStructMemberContext => Ok(ExStructMemberContext::new(asset)?.into()),
EExprToken::ExLetMulticastDelegate => Ok(ExLetMulticastDelegate::new(asset)?.into()),
EExprToken::ExLetDelegate => Ok(ExLetDelegate::new(asset)?.into()),
EExprToken::ExLocalVirtualFunction => Ok(ExLocalVirtualFunction::new(asset)?.into()),
EExprToken::ExLocalFinalFunction => Ok(ExLocalFinalFunction::new(asset)?.into()),
EExprToken::ExLocalOutVariable => Ok(ExLocalOutVariable::new(asset)?.into()),
EExprToken::ExDeprecatedOp4A => Ok(ExDeprecatedOp4A::new(asset)?.into()),
EExprToken::ExInstanceDelegate => Ok(ExInstanceDelegate::new(asset)?.into()),
EExprToken::ExPushExecutionFlow => Ok(ExPushExecutionFlow::new(asset)?.into()),
EExprToken::ExPopExecutionFlow => Ok(ExPopExecutionFlow::new(asset)?.into()),
EExprToken::ExComputedJump => Ok(ExComputedJump::new(asset)?.into()),
EExprToken::ExPopExecutionFlowIfNot => Ok(ExPopExecutionFlowIfNot::new(asset)?.into()),
EExprToken::ExBreakpoint => Ok(ExBreakpoint::new(asset)?.into()),
EExprToken::ExInterfaceContext => Ok(ExInterfaceContext::new(asset)?.into()),
EExprToken::ExObjToInterfaceCast => Ok(ExObjToInterfaceCast::new(asset)?.into()),
EExprToken::ExEndOfScript => Ok(ExEndOfScript::new(asset)?.into()),
EExprToken::ExCrossInterfaceCast => Ok(ExCrossInterfaceCast::new(asset)?.into()),
EExprToken::ExInterfaceToObjCast => Ok(ExInterfaceToObjCast::new(asset)?.into()),
EExprToken::ExWireTracepoint => Ok(ExWireTracepoint::new(asset)?.into()),
EExprToken::ExSkipOffsetConst => Ok(ExSkipOffsetConst::new(asset)?.into()),
EExprToken::ExAddMulticastDelegate => Ok(ExAddMulticastDelegate::new(asset)?.into()),
EExprToken::ExClearMulticastDelegate => {
Ok(ExClearMulticastDelegate::new(asset)?.into())
}
EExprToken::ExTracepoint => Ok(ExTracepoint::new(asset)?.into()),
EExprToken::ExLetObj => Ok(ExLetObj::new(asset)?.into()),
EExprToken::ExLetWeakObjPtr => Ok(ExLetWeakObjPtr::new(asset)?.into()),
EExprToken::ExBindDelegate => Ok(ExBindDelegate::new(asset)?.into()),
EExprToken::ExRemoveMulticastDelegate => {
Ok(ExRemoveMulticastDelegate::new(asset)?.into())
}
EExprToken::ExCallMulticastDelegate => Ok(ExCallMulticastDelegate::new(asset)?.into()),
EExprToken::ExLetValueOnPersistentFrame => {
Ok(ExLetValueOnPersistentFrame::new(asset)?.into())
}
EExprToken::ExArrayConst => Ok(ExArrayConst::new(asset)?.into()),
EExprToken::ExEndArrayConst => Ok(ExEndArrayConst::new(asset)?.into()),
EExprToken::ExSoftObjectConst => Ok(ExSoftObjectConst::new(asset)?.into()),
EExprToken::ExCallMath => Ok(ExCallMath::new(asset)?.into()),
EExprToken::ExSwitchValue => Ok(ExSwitchValue::new(asset)?.into()),
EExprToken::ExInstrumentationEvent => Ok(ExInstrumentationEvent::new(asset)?.into()),
EExprToken::ExArrayGetByRef => Ok(ExArrayGetByRef::new(asset)?.into()),
EExprToken::ExClassSparseDataVariable => {
Ok(ExClassSparseDataVariable::new(asset)?.into())
}
EExprToken::ExFieldPathConst => Ok(ExFieldPathConst::new(asset)?.into()),
_ => Err(KismetError::expression(format!(
"Unknown kismet expression {}",
token as i32
))
.into()),
};
expr
}
pub fn read_arr<Reader: ArchiveReader>(
asset: &mut Reader,
end_token: EExprToken,
) -> Result<Vec<Self>, Error> {
let mut data = Vec::new();
let mut current_expr: Option<KismetExpression> = None;
while current_expr.is_none() || !current_expr.as_ref().unwrap().enum_eq(&end_token) {
if let Some(expr) = current_expr {
data.push(expr);
}
current_expr = KismetExpression::new(asset).ok();
}
Ok(data)
}
pub fn write<Writer: ArchiveWriter>(
expr: &KismetExpression,
asset: &mut Writer,
) -> Result<usize, Error> {
asset.write_u8(expr.get_token().into())?;
Ok(expr.write(asset)? + size_of::<u8>())
}
}
declare_expression!(
ExFieldPathConst,
value: Box<KismetExpression>
);
impl ExFieldPathConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExFieldPathConst {
token: EExprToken::ExFieldPathConst,
value: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExFieldPathConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.value.as_ref(), asset)
}
}
declare_expression!(
ExNameConst,
value: FName
);
impl ExNameConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExNameConst {
token: EExprToken::ExNameConst,
value: asset.read_fname()?,
})
}
}
impl KismetExpressionTrait for ExNameConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_fname(&self.value)?;
Ok(12)
}
}
declare_expression!(
ExObjectConst,
#[container_ignore]
value: PackageIndex
);
impl ExObjectConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExObjectConst {
token: EExprToken::ExObjectConst,
value: PackageIndex::new(asset.read_i32::<LE>()?),
})
}
}
impl KismetExpressionTrait for ExObjectConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_i32::<LE>(self.value.index)?;
Ok(size_of::<u64>())
}
}
declare_expression!(
ExSoftObjectConst,
value: Box<KismetExpression>
);
impl ExSoftObjectConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExSoftObjectConst {
token: EExprToken::ExSoftObjectConst,
value: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExSoftObjectConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.value.as_ref(), asset)
}
}
declare_expression!(
ExTransformConst,
#[container_ignore]
value: Transform<OrderedFloat<f64>>
);
impl ExTransformConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let transform =
match asset.get_object_version_ue5() >= ObjectVersionUE5::LARGE_WORLD_COORDINATES {
true => {
let rotation = Vector4::new(
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
);
let translation = Vector::new(
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
);
let scale = Vector::new(
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
);
Transform::new(rotation, translation, scale)
}
false => {
let rotation = Vector4::new(
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
);
let translation = Vector::new(
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
);
let scale = Vector::new(
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
);
Transform::new(rotation, translation, scale)
}
};
Ok(ExTransformConst {
token: EExprToken::ExTransformConst,
value: transform,
})
}
}
impl KismetExpressionTrait for ExTransformConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
match asset.get_object_version_ue5() >= ObjectVersionUE5::LARGE_WORLD_COORDINATES {
true => {
asset.write_f64::<LE>(self.value.rotation.x.0)?;
asset.write_f64::<LE>(self.value.rotation.y.0)?;
asset.write_f64::<LE>(self.value.rotation.z.0)?;
asset.write_f64::<LE>(self.value.rotation.w.0)?;
asset.write_f64::<LE>(self.value.translation.x.0)?;
asset.write_f64::<LE>(self.value.translation.y.0)?;
asset.write_f64::<LE>(self.value.translation.z.0)?;
asset.write_f64::<LE>(self.value.scale.x.0)?;
asset.write_f64::<LE>(self.value.scale.y.0)?;
asset.write_f64::<LE>(self.value.scale.z.0)?;
Ok(size_of::<f64>() * 10)
}
false => {
asset.write_f32::<LE>(self.value.rotation.x.0 as f32)?;
asset.write_f32::<LE>(self.value.rotation.y.0 as f32)?;
asset.write_f32::<LE>(self.value.rotation.z.0 as f32)?;
asset.write_f32::<LE>(self.value.rotation.w.0 as f32)?;
asset.write_f32::<LE>(self.value.translation.x.0 as f32)?;
asset.write_f32::<LE>(self.value.translation.y.0 as f32)?;
asset.write_f32::<LE>(self.value.translation.z.0 as f32)?;
asset.write_f32::<LE>(self.value.scale.x.0 as f32)?;
asset.write_f32::<LE>(self.value.scale.y.0 as f32)?;
asset.write_f32::<LE>(self.value.scale.z.0 as f32)?;
Ok(size_of::<f32>() * 10)
}
}
}
}
declare_expression!(
ExVectorConst,
#[container_ignore]
value: Vector<OrderedFloat<f64>>
);
impl ExVectorConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let value =
match asset.get_object_version_ue5() >= ObjectVersionUE5::LARGE_WORLD_COORDINATES {
true => Vector::new(
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
OrderedFloat(asset.read_f64::<LE>()?),
),
false => Vector::new(
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
OrderedFloat(asset.read_f32::<LE>()? as f64),
),
};
Ok(ExVectorConst {
token: EExprToken::ExVectorConst,
value,
})
}
}
impl KismetExpressionTrait for ExVectorConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
match asset.get_object_version_ue5() >= ObjectVersionUE5::LARGE_WORLD_COORDINATES {
true => {
asset.write_f64::<LE>(self.value.x.0)?;
asset.write_f64::<LE>(self.value.y.0)?;
asset.write_f64::<LE>(self.value.z.0)?;
Ok(size_of::<f64>() * 3)
}
false => {
asset.write_f32::<LE>(self.value.x.0 as f32)?;
asset.write_f32::<LE>(self.value.y.0 as f32)?;
asset.write_f32::<LE>(self.value.z.0 as f32)?;
Ok(size_of::<f32>() * 3)
}
}
}
}
declare_expression!(
ExTextConst,
value: Box<FScriptText>
);
impl ExTextConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExTextConst {
token: EExprToken::ExTextConst,
value: Box::new(FScriptText::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExTextConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.value.write(asset)
}
}
declare_expression!(
ExAddMulticastDelegate,
delegate: Box<KismetExpression>,
delegate_to_add: Box<KismetExpression>
);
impl ExAddMulticastDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExAddMulticastDelegate {
token: EExprToken::ExAddMulticastDelegate,
delegate: Box::new(KismetExpression::new(asset)?),
delegate_to_add: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExAddMulticastDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.delegate.as_ref(), asset)?
+ KismetExpression::write(self.delegate_to_add.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExArrayConst,
inner_property: KismetPropertyPointer,
elements: Vec<KismetExpression>
);
impl ExArrayConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let inner_property = KismetPropertyPointer::new(asset)?;
asset.read_i32::<LE>()?; let elements = KismetExpression::read_arr(asset, EExprToken::ExEndArrayConst)?;
Ok(ExArrayConst {
token: EExprToken::ExArrayConst,
inner_property,
elements,
})
}
}
impl KismetExpressionTrait for ExArrayConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<i32>();
offset += self.inner_property.write(asset)?;
asset.write_i32::<LE>(self.elements.len() as i32)?;
for element in &self.elements {
offset += KismetExpression::write(element, asset)?;
}
offset += KismetExpression::write(&ExEndArrayConst::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExArrayGetByRef,
array_variable: Box<KismetExpression>,
array_index: Box<KismetExpression>
);
impl ExArrayGetByRef {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExArrayGetByRef {
token: EExprToken::ExArrayGetByRef,
array_variable: Box::new(KismetExpression::new(asset)?),
array_index: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExArrayGetByRef {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.array_variable.as_ref(), asset)?
+ KismetExpression::write(self.array_index.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExAssert,
line_number: u16,
debug_mode: bool,
assert_expression: Box<KismetExpression>
);
impl ExAssert {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExAssert {
token: EExprToken::ExAssert,
line_number: asset.read_u16::<LE>()?,
debug_mode: asset.read_bool()?,
assert_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExAssert {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_u16::<LE>(self.line_number)?;
asset.write_bool(self.debug_mode)?;
let offset = size_of::<u32>()
+ size_of::<bool>()
+ KismetExpression::write(self.assert_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExBindDelegate,
function_name: FName,
delegate: Box<KismetExpression>,
object_term: Box<KismetExpression>
);
impl ExBindDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExBindDelegate {
token: EExprToken::ExBindDelegate,
function_name: asset.read_fname()?,
delegate: Box::new(KismetExpression::new(asset)?),
object_term: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExBindDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_fname(&self.function_name)?;
let offset = 12 +
KismetExpression::write(self.delegate.as_ref(), asset)? +
KismetExpression::write(self.object_term.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExCallMath,
#[container_ignore]
stack_node: PackageIndex,
parameters: Vec<KismetExpression>
);
impl ExCallMath {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExCallMath {
token: EExprToken::ExCallMath,
stack_node: PackageIndex::new(asset.read_i32::<LE>()?),
parameters: KismetExpression::read_arr(asset, EExprToken::ExEndFunctionParms)?,
})
}
}
impl KismetExpressionTrait for ExCallMath {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.stack_node.index)?;
for parameter in &self.parameters {
offset += KismetExpression::write(parameter, asset)?;
}
offset += KismetExpression::write(&ExEndFunctionParms::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExCallMulticastDelegate,
#[container_ignore]
stack_node: PackageIndex,
parameters: Vec<KismetExpression>,
delegate: Box<KismetExpression>
);
impl ExCallMulticastDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let stack_node = PackageIndex::new(asset.read_i32::<LE>()?);
let delegate = KismetExpression::new(asset)?;
let parameters = KismetExpression::read_arr(asset, EExprToken::ExEndFunctionParms)?;
Ok(ExCallMulticastDelegate {
token: EExprToken::ExCallMulticastDelegate,
stack_node,
parameters,
delegate: Box::new(delegate),
})
}
}
impl KismetExpressionTrait for ExCallMulticastDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.stack_node.index)?;
offset += KismetExpression::write(&self.delegate, asset)?;
for parameter in &self.parameters {
offset += KismetExpression::write(parameter, asset)?;
}
offset += KismetExpression::write(&ExEndFunctionParms::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExClassContext,
object_expression: Box<KismetExpression>,
offset: u32,
r_value_pointer: KismetPropertyPointer,
context_expression: Box<KismetExpression>
);
impl ExClassContext {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExClassContext {
token: EExprToken::ExClassContext,
object_expression: Box::new(KismetExpression::new(asset)?),
offset: asset.read_u32::<LE>()?,
r_value_pointer: KismetPropertyPointer::new(asset)?,
context_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExClassContext {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u32>();
offset += KismetExpression::write(self.object_expression.as_ref(), asset)?;
asset.write_u32::<LE>(self.offset)?;
offset += self.r_value_pointer.write(asset)?;
offset += KismetExpression::write(self.context_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExClassSparseDataVariable,
variable: KismetPropertyPointer
);
impl ExClassSparseDataVariable {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExClassSparseDataVariable {
token: EExprToken::ExClassSparseDataVariable,
variable: KismetPropertyPointer::new(asset)?,
})
}
}
impl KismetExpressionTrait for ExClassSparseDataVariable {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.variable.write(asset)
}
}
declare_expression!(
ExClearMulticastDelegate,
delegate_to_clear: Box<KismetExpression>
);
impl ExClearMulticastDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExClearMulticastDelegate {
token: EExprToken::ExClearMulticastDelegate,
delegate_to_clear: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExClearMulticastDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.delegate_to_clear.as_ref(), asset)
}
}
declare_expression!(
ExComputedJump,
code_offset_expression: Box<KismetExpression>
);
impl ExComputedJump {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExComputedJump {
token: EExprToken::ExComputedJump,
code_offset_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExComputedJump {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.code_offset_expression.as_ref(), asset)
}
}
declare_expression!(
ExContext,
object_expression: Box<KismetExpression>,
offset: u32,
r_value_pointer: KismetPropertyPointer,
context_expression: Box<KismetExpression>
);
impl ExContext {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExContext {
token: EExprToken::ExContext,
object_expression: Box::new(KismetExpression::new(asset)?),
offset: asset.read_u32::<LE>()?,
r_value_pointer: KismetPropertyPointer::new(asset)?,
context_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExContext {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u32>();
offset += KismetExpression::write(self.object_expression.as_ref(), asset)?;
asset.write_u32::<LE>(self.offset)?;
offset += self.r_value_pointer.write(asset)?;
offset += KismetExpression::write(self.context_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExContextFailSilent,
object_expression: Box<KismetExpression>,
offset: u32,
r_value_pointer: KismetPropertyPointer,
context_expression: Box<KismetExpression>
);
impl ExContextFailSilent {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExContextFailSilent {
token: EExprToken::ExContextFailSilent,
object_expression: Box::new(KismetExpression::new(asset)?),
offset: asset.read_u32::<LE>()?,
r_value_pointer: KismetPropertyPointer::new(asset)?,
context_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExContextFailSilent {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u32>();
offset += KismetExpression::write(self.object_expression.as_ref(), asset)?;
asset.write_u32::<LE>(self.offset)?;
offset += self.r_value_pointer.write(asset)?;
offset += KismetExpression::write(self.context_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExCrossInterfaceCast,
#[container_ignore]
class_ptr: PackageIndex,
target: Box<KismetExpression>
);
impl ExCrossInterfaceCast {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExCrossInterfaceCast {
token: EExprToken::ExCrossInterfaceCast,
class_ptr: PackageIndex::new(asset.read_i32::<LE>()?),
target: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExCrossInterfaceCast {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.class_ptr.index)?;
offset += KismetExpression::write(self.target.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExDefaultVariable,
variable: KismetPropertyPointer
);
impl ExDefaultVariable {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExDefaultVariable {
token: EExprToken::ExDefaultVariable,
variable: KismetPropertyPointer::new(asset)?,
})
}
}
impl KismetExpressionTrait for ExDefaultVariable {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.variable.write(asset)
}
}
declare_expression!(
ExDynamicCast,
#[container_ignore]
class_ptr: PackageIndex,
target_expression: Box<KismetExpression>
);
impl ExDynamicCast {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExDynamicCast {
token: EExprToken::ExDynamicCast,
class_ptr: PackageIndex::new(asset.read_i32::<LE>()?),
target_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExDynamicCast {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.class_ptr.index)?;
offset += KismetExpression::write(self.target_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExFinalFunction,
#[container_ignore]
stack_node: PackageIndex,
parameters: Vec<KismetExpression>
);
impl ExFinalFunction {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExFinalFunction {
token: EExprToken::ExFinalFunction,
stack_node: PackageIndex::new(asset.read_i32::<LE>()?),
parameters: KismetExpression::read_arr(asset, EExprToken::ExEndFunctionParms)?,
})
}
}
impl KismetExpressionTrait for ExFinalFunction {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.stack_node.index)?;
for parameter in &self.parameters {
offset += KismetExpression::write(parameter, asset)?;
}
offset += KismetExpression::write(&ExEndFunctionParms::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExInstanceDelegate,
function_name: FName
);
impl ExInstanceDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExInstanceDelegate {
token: EExprToken::ExInstanceDelegate,
function_name: asset.read_fname()?,
})
}
}
impl KismetExpressionTrait for ExInstanceDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_fname(&self.function_name)?;
Ok(12) }
}
declare_expression!(
ExInstanceVariable,
variable: KismetPropertyPointer
);
impl ExInstanceVariable {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExInstanceVariable {
token: EExprToken::ExInstanceVariable,
variable: KismetPropertyPointer::new(asset)?,
})
}
}
impl KismetExpressionTrait for ExInstanceVariable {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.variable.write(asset)
}
}
declare_expression!(
ExInterfaceContext,
interface_value: Box<KismetExpression>
);
impl ExInterfaceContext {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExInterfaceContext {
token: EExprToken::ExInterfaceContext,
interface_value: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExInterfaceContext {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.interface_value.as_ref(), asset)
}
}
declare_expression!(
ExInterfaceToObjCast,
#[container_ignore]
class_ptr: PackageIndex,
target: Box<KismetExpression>
);
impl ExInterfaceToObjCast {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExInterfaceToObjCast {
token: EExprToken::ExInterfaceToObjCast,
class_ptr: PackageIndex::new(asset.read_i32::<LE>()?),
target: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExInterfaceToObjCast {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.class_ptr.index)?;
offset += KismetExpression::write(self.target.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExJump,
code_offset: u32
);
impl ExJump {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExJump {
token: EExprToken::ExJump,
code_offset: asset.read_u32::<LE>()?,
})
}
}
impl KismetExpressionTrait for ExJump {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_u32::<LE>(self.code_offset)?;
Ok(size_of::<u32>())
}
}
declare_expression!(
ExJumpIfNot,
code_offset: u32,
boolean_expression: Box<KismetExpression>
);
impl ExJumpIfNot {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExJumpIfNot {
token: EExprToken::ExJumpIfNot,
code_offset: asset.read_u32::<LE>()?,
boolean_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExJumpIfNot {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u32>();
asset.write_u32::<LE>(self.code_offset)?;
offset += KismetExpression::write(self.boolean_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLet,
value: KismetPropertyPointer,
variable: Box<KismetExpression>,
expression: Box<KismetExpression>
);
impl ExLet {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLet {
token: EExprToken::ExLet,
value: KismetPropertyPointer::new(asset)?,
variable: Box::new(KismetExpression::new(asset)?),
expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLet {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = self.value.write(asset)?;
offset += KismetExpression::write(self.variable.as_ref(), asset)?;
offset += KismetExpression::write(self.expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLetBool,
variable_expression: Box<KismetExpression>,
assignment_expression: Box<KismetExpression>
);
impl ExLetBool {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLetBool {
token: EExprToken::ExLetBool,
variable_expression: Box::new(KismetExpression::new(asset)?),
assignment_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLetBool {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.variable_expression.as_ref(), asset)?
+ KismetExpression::write(self.assignment_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLetDelegate,
variable_expression: Box<KismetExpression>,
assignment_expression: Box<KismetExpression>
);
impl ExLetDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLetDelegate {
token: EExprToken::ExLetDelegate,
variable_expression: Box::new(KismetExpression::new(asset)?),
assignment_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLetDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.variable_expression.as_ref(), asset)?
+ KismetExpression::write(self.assignment_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLetMulticastDelegate,
variable_expression: Box<KismetExpression>,
assignment_expression: Box<KismetExpression>
);
impl ExLetMulticastDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLetMulticastDelegate {
token: EExprToken::ExLetMulticastDelegate,
variable_expression: Box::new(KismetExpression::new(asset)?),
assignment_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLetMulticastDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.variable_expression.as_ref(), asset)?
+ KismetExpression::write(self.assignment_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLetObj,
variable_expression: Box<KismetExpression>,
assignment_expression: Box<KismetExpression>
);
impl ExLetObj {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLetObj {
token: EExprToken::ExLetObj,
variable_expression: Box::new(KismetExpression::new(asset)?),
assignment_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLetObj {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.variable_expression.as_ref(), asset)?
+ KismetExpression::write(self.assignment_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLetValueOnPersistentFrame,
destination_property: KismetPropertyPointer,
assignment_expression: Box<KismetExpression>
);
impl ExLetValueOnPersistentFrame {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLetValueOnPersistentFrame {
token: EExprToken::ExLetValueOnPersistentFrame,
destination_property: KismetPropertyPointer::new(asset)?,
assignment_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLetValueOnPersistentFrame {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = self.destination_property.write(asset)?
+ KismetExpression::write(self.assignment_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLetWeakObjPtr,
variable_expression: Box<KismetExpression>,
assignment_expression: Box<KismetExpression>
);
impl ExLetWeakObjPtr {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLetWeakObjPtr {
token: EExprToken::ExLetWeakObjPtr,
variable_expression: Box::new(KismetExpression::new(asset)?),
assignment_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExLetWeakObjPtr {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.variable_expression.as_ref(), asset)?
+ KismetExpression::write(self.assignment_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLocalFinalFunction,
#[container_ignore]
stack_node: PackageIndex,
parameters: Vec<KismetExpression>
);
impl ExLocalFinalFunction {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLocalFinalFunction {
token: EExprToken::ExLocalFinalFunction,
stack_node: PackageIndex::new(asset.read_i32::<LE>()?),
parameters: KismetExpression::read_arr(asset, EExprToken::ExEndFunctionParms)?,
})
}
}
impl KismetExpressionTrait for ExLocalFinalFunction {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.stack_node.index)?;
for parameter in &self.parameters {
offset += KismetExpression::write(parameter, asset)?;
}
offset += KismetExpression::write(&ExEndFunctionParms::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExLocalOutVariable,
variable: KismetPropertyPointer
);
impl ExLocalOutVariable {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLocalOutVariable {
token: EExprToken::ExLocalOutVariable,
variable: KismetPropertyPointer::new(asset)?,
})
}
}
impl KismetExpressionTrait for ExLocalOutVariable {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.variable.write(asset)
}
}
declare_expression!(
ExLocalVariable,
variable: KismetPropertyPointer
);
impl ExLocalVariable {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLocalVariable {
token: EExprToken::ExLocalVariable,
variable: KismetPropertyPointer::new(asset)?,
})
}
}
impl KismetExpressionTrait for ExLocalVariable {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.variable.write(asset)
}
}
declare_expression!(
ExLocalVirtualFunction,
virtual_function_name: FName,
parameters: Vec<KismetExpression>
);
impl ExLocalVirtualFunction {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExLocalVirtualFunction {
token: EExprToken::ExLocalVirtualFunction,
virtual_function_name: asset.read_fname()?,
parameters: KismetExpression::read_arr(asset, EExprToken::ExEndFunctionParms)?,
})
}
}
impl KismetExpressionTrait for ExLocalVirtualFunction {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = 12; asset.write_fname(&self.virtual_function_name)?;
for parameter in &self.parameters {
offset += KismetExpression::write(parameter, asset)?;
}
offset += KismetExpression::write(&ExEndFunctionParms::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExMapConst,
key_property: KismetPropertyPointer,
value_property: KismetPropertyPointer,
elements: Vec<KismetExpression>
);
impl ExMapConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let key_property = KismetPropertyPointer::new(asset)?;
let value_property = KismetPropertyPointer::new(asset)?;
let _num_entries = asset.read_i32::<LE>()?;
let elements = KismetExpression::read_arr(asset, EExprToken::ExEndMapConst)?;
Ok(ExMapConst {
token: EExprToken::ExMapConst,
key_property,
value_property,
elements,
})
}
}
impl KismetExpressionTrait for ExMapConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<i32>();
offset += self.key_property.write(asset)?;
offset += self.value_property.write(asset)?;
asset.write_i32::<LE>(self.elements.len() as i32)?;
for element in &self.elements {
offset += KismetExpression::write(element, asset)?;
}
offset += KismetExpression::write(&ExEndMapConst::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExMetaCast,
#[container_ignore]
class_ptr: PackageIndex,
target_expression: Box<KismetExpression>
);
impl ExMetaCast {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExMetaCast {
token: EExprToken::ExMetaCast,
class_ptr: PackageIndex::new(asset.read_i32::<LE>()?),
target_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExMetaCast {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.class_ptr.index)?;
offset += KismetExpression::write(self.target_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExObjToInterfaceCast,
#[container_ignore]
class_ptr: PackageIndex,
target: Box<KismetExpression>
);
impl ExObjToInterfaceCast {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExObjToInterfaceCast {
token: EExprToken::ExObjToInterfaceCast,
class_ptr: PackageIndex::new(asset.read_i32::<LE>()?),
target: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExObjToInterfaceCast {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>();
asset.write_i32::<LE>(self.class_ptr.index)?;
offset += KismetExpression::write(self.target.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExPopExecutionFlowIfNot,
boolean_expression: Box<KismetExpression>
);
impl ExPopExecutionFlowIfNot {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExPopExecutionFlowIfNot {
token: EExprToken::ExPopExecutionFlowIfNot,
boolean_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExPopExecutionFlowIfNot {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.boolean_expression.as_ref(), asset)
}
}
declare_expression!(
ExPrimitiveCast,
#[container_ignore]
conversion_type: ECastToken,
target: Box<KismetExpression>
);
impl ExPrimitiveCast {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExPrimitiveCast {
token: EExprToken::ExPrimitiveCast,
conversion_type: asset.read_u8()?.try_into()?,
target: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExPrimitiveCast {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u8>();
asset.write_u8(self.conversion_type.into())?;
offset += KismetExpression::write(self.target.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExPropertyConst,
property: KismetPropertyPointer
);
impl ExPropertyConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExPropertyConst {
token: EExprToken::ExPropertyConst,
property: KismetPropertyPointer::new(asset)?,
})
}
}
impl KismetExpressionTrait for ExPropertyConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
self.property.write(asset)
}
}
declare_expression!(
ExPushExecutionFlow,
pushing_address: u32
);
impl ExPushExecutionFlow {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExPushExecutionFlow {
token: EExprToken::ExPushExecutionFlow,
pushing_address: asset.read_u32::<LE>()?,
})
}
}
impl KismetExpressionTrait for ExPushExecutionFlow {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_u32::<LE>(self.pushing_address)?;
Ok(size_of::<u32>())
}
}
declare_expression!(
ExRemoveMulticastDelegate,
delegate: Box<KismetExpression>,
delegate_to_add: Box<KismetExpression>
);
impl ExRemoveMulticastDelegate {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExRemoveMulticastDelegate {
token: EExprToken::ExRemoveMulticastDelegate,
delegate: Box::new(KismetExpression::new(asset)?),
delegate_to_add: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExRemoveMulticastDelegate {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let offset = KismetExpression::write(self.delegate.as_ref(), asset)?
+ KismetExpression::write(self.delegate_to_add.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExReturn,
return_expression: Box<KismetExpression>
);
impl ExReturn {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExReturn {
token: EExprToken::ExReturn,
return_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExReturn {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
KismetExpression::write(self.return_expression.as_ref(), asset)
}
}
declare_expression!(
ExRotationConst,
#[container_ignore]
rotator: Vector<OrderedFloat<f64>>
);
impl ExRotationConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let rotator =
match asset.get_object_version_ue5() >= ObjectVersionUE5::LARGE_WORLD_COORDINATES {
true => {
let pitch = asset.read_f64::<LE>()?;
let yaw = asset.read_f64::<LE>()?;
let roll = asset.read_f64::<LE>()?;
Vector::new(OrderedFloat(pitch), OrderedFloat(yaw), OrderedFloat(roll))
}
false => {
let pitch = asset.read_f32::<LE>()?;
let yaw = asset.read_f32::<LE>()?;
let roll = asset.read_f32::<LE>()?;
Vector::new(
OrderedFloat(pitch as f64),
OrderedFloat(yaw as f64),
OrderedFloat(roll as f64),
)
}
};
Ok(ExRotationConst {
token: EExprToken::ExRotationConst,
rotator,
})
}
}
impl KismetExpressionTrait for ExRotationConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
match asset.get_object_version_ue5() >= ObjectVersionUE5::LARGE_WORLD_COORDINATES {
true => {
asset.write_f64::<LE>(self.rotator.x.0)?;
asset.write_f64::<LE>(self.rotator.y.0)?;
asset.write_f64::<LE>(self.rotator.z.0)?;
Ok(size_of::<f64>() * 3)
}
false => {
asset.write_f32::<LE>(self.rotator.x.0 as f32)?;
asset.write_f32::<LE>(self.rotator.y.0 as f32)?;
asset.write_f32::<LE>(self.rotator.z.0 as f32)?;
Ok(size_of::<f32>() * 3)
}
}
}
}
declare_expression!(
ExSetArray,
assigning_property: Option<Box<KismetExpression>>,
#[container_ignore]
array_inner_prop: Option<PackageIndex>,
elements: Vec<KismetExpression>
);
impl ExSetArray {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let (assigning_property, array_inner_prop) =
match asset.get_object_version() >= ObjectVersion::VER_UE4_CHANGE_SETARRAY_BYTECODE {
true => (Some(Box::new(KismetExpression::new(asset)?)), None),
false => (None, Some(PackageIndex::new(asset.read_i32::<LE>()?))),
};
Ok(ExSetArray {
token: EExprToken::ExSetArray,
assigning_property,
array_inner_prop,
elements: KismetExpression::read_arr(asset, EExprToken::ExEndArray)?,
})
}
}
impl KismetExpressionTrait for ExSetArray {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = 0;
if asset.get_object_version() >= ObjectVersion::VER_UE4_CHANGE_SETARRAY_BYTECODE {
offset += KismetExpression::write(
self.assigning_property.as_ref().ok_or_else(|| {
Error::no_data(
"engine_version >= UE4_CHANGE_SETARRAY_BYTECODE but assigning_property is None"
.to_string(),
)
})?,
asset,
)?;
} else {
asset.write_i32::<LE>(self.array_inner_prop.map(|e| e.index).ok_or_else(|| {
Error::no_data(
"engine_version < UE4_CHANGE_SETARRAY_BYTECODE but array_inner_prop is None"
.to_string(),
)
})?)?;
offset += size_of::<u64>();
}
for element in &self.elements {
offset += KismetExpression::write(element, asset)?;
}
offset += KismetExpression::write(&ExEndArray::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExSetConst,
inner_property: KismetPropertyPointer,
elements: Vec<KismetExpression>
);
impl ExSetConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let inner_property = KismetPropertyPointer::new(asset)?;
let _num_entries = asset.read_i32::<LE>()?;
let elements = KismetExpression::read_arr(asset, EExprToken::ExEndSetConst)?;
Ok(ExSetConst {
token: EExprToken::ExSetConst,
inner_property,
elements,
})
}
}
impl KismetExpressionTrait for ExSetConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<i32>();
offset += self.inner_property.write(asset)?;
asset.write_i32::<LE>(self.elements.len() as i32)?;
for element in &self.elements {
offset += KismetExpression::write(element, asset)?;
}
offset += KismetExpression::write(&ExEndSetConst::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExSetMap,
map_property: Box<KismetExpression>,
elements: Vec<KismetExpression>
);
impl ExSetMap {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let map_property = Box::new(KismetExpression::new(asset)?);
let _num_entries = asset.read_i32::<LE>()?;
let elements = KismetExpression::read_arr(asset, EExprToken::ExEndMap)?;
Ok(ExSetMap {
token: EExprToken::ExSetMap,
map_property,
elements,
})
}
}
impl KismetExpressionTrait for ExSetMap {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<i32>();
offset += KismetExpression::write(self.map_property.as_ref(), asset)?;
asset.write_i32::<LE>(self.elements.len() as i32)?;
for element in &self.elements {
offset += KismetExpression::write(element, asset)?;
}
offset += KismetExpression::write(&ExEndMap::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExSetSet,
set_property: Box<KismetExpression>,
elements: Vec<KismetExpression>
);
impl ExSetSet {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let set_property = Box::new(KismetExpression::new(asset)?);
let _num_entries = asset.read_i32::<LE>()?;
let elements = KismetExpression::read_arr(asset, EExprToken::ExEndSet)?;
Ok(ExSetSet {
token: EExprToken::ExSetSet,
set_property,
elements,
})
}
}
impl KismetExpressionTrait for ExSetSet {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<i32>();
offset += KismetExpression::write(self.set_property.as_ref(), asset)?;
asset.write_i32::<LE>(self.elements.len() as i32)?;
for element in &self.elements {
offset += KismetExpression::write(element, asset)?;
}
offset += KismetExpression::write(&ExEndSet::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExSkip,
code_offset: u32,
skip_expression: Box<KismetExpression>
);
impl ExSkip {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExSkip {
token: EExprToken::ExSkip,
code_offset: asset.read_u32::<LE>()?,
skip_expression: Box::new(KismetExpression::new(asset)?),
})
}
}
impl KismetExpressionTrait for ExSkip {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u32>();
asset.write_u32::<LE>(self.code_offset)?;
offset += KismetExpression::write(self.skip_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExStructConst,
#[container_ignore]
struct_value: PackageIndex,
struct_size: i32,
value: Vec<KismetExpression>
);
impl ExStructConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExStructConst {
token: EExprToken::ExStructConst,
struct_value: PackageIndex::new(asset.read_i32::<LE>()?),
struct_size: asset.read_i32::<LE>()?,
value: KismetExpression::read_arr(asset, EExprToken::ExEndStructConst)?,
})
}
}
impl KismetExpressionTrait for ExStructConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u64>() + size_of::<i32>();
asset.write_i32::<LE>(self.struct_value.index)?;
asset.write_i32::<LE>(self.struct_size)?;
for entry in &self.value {
offset += KismetExpression::write(entry, asset)?;
}
offset += KismetExpression::write(&ExEndStructConst::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExStructMemberContext,
struct_member_expression: KismetPropertyPointer,
struct_expression: Box<KismetExpression>
);
impl ExStructMemberContext {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let struct_member_expression = KismetPropertyPointer::new(asset)?;
let struct_expression = KismetExpression::new(asset)?;
Ok(ExStructMemberContext {
token: EExprToken::ExStructMemberContext,
struct_member_expression,
struct_expression: Box::new(struct_expression),
})
}
}
impl KismetExpressionTrait for ExStructMemberContext {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = 0;
offset += self.struct_member_expression.write(asset)?;
offset += KismetExpression::write(self.struct_expression.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExSwitchValue,
end_goto_offset: u32,
index_term: Box<KismetExpression>,
default_term: Box<KismetExpression>,
cases: Vec<KismetSwitchCase>
);
impl ExSwitchValue {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let num_cases = asset.read_u16::<LE>()?;
let end_goto_offset = asset.read_u32::<LE>()?;
let index_term = Box::new(KismetExpression::new(asset)?);
let mut cases = Vec::with_capacity(num_cases as usize);
for _i in 0..num_cases as usize {
let term_a = KismetExpression::new(asset)?;
let term_b = asset.read_u32::<LE>()?;
let term_c = KismetExpression::new(asset)?;
cases.push(KismetSwitchCase::new(term_a, term_b, term_c));
}
let default_term = Box::new(KismetExpression::new(asset)?);
Ok(ExSwitchValue {
token: EExprToken::ExSwitchValue,
end_goto_offset,
index_term,
default_term,
cases,
})
}
}
impl KismetExpressionTrait for ExSwitchValue {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = size_of::<u16>() + size_of::<u32>();
asset.write_u16::<LE>(self.cases.len() as u16)?;
asset.write_u32::<LE>(self.end_goto_offset)?;
offset += KismetExpression::write(self.index_term.as_ref(), asset)?;
for case in &self.cases {
offset += KismetExpression::write(&case.case_index_value_term, asset)?;
offset += size_of::<u32>();
asset.write_u32::<LE>(case.next_offset)?;
offset += KismetExpression::write(&case.case_term, asset)?;
}
offset += KismetExpression::write(self.default_term.as_ref(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExVirtualFunction,
virtual_function_name: FName,
parameters: Vec<KismetExpression>
);
impl ExVirtualFunction {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExVirtualFunction {
token: EExprToken::ExVirtualFunction,
virtual_function_name: asset.read_fname()?,
parameters: KismetExpression::read_arr(asset, EExprToken::ExEndFunctionParms)?,
})
}
}
impl KismetExpressionTrait for ExVirtualFunction {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
let mut offset = 12; asset.write_fname(&self.virtual_function_name)?;
for parameter in &self.parameters {
offset += KismetExpression::write(parameter, asset)?;
}
offset += KismetExpression::write(&ExEndFunctionParms::default().into(), asset)?;
Ok(offset)
}
}
declare_expression!(
ExStringConst,
value: String
);
impl ExStringConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExStringConst {
token: EExprToken::ExStringConst,
value: read_kismet_string(asset)?,
})
}
}
impl KismetExpressionTrait for ExStringConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
write_kismet_string(&self.value, asset)
}
}
declare_expression!(
ExUnicodeStringConst,
value: String
);
impl ExUnicodeStringConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExUnicodeStringConst {
token: EExprToken::ExUnicodeStringConst,
value: read_kismet_unicode_string(asset)?,
})
}
}
impl KismetExpressionTrait for ExUnicodeStringConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
write_kismet_unicode_string(&self.value, asset)
}
}
declare_expression!(
ExInstrumentationEvent,
#[container_ignore]
event_type: EScriptInstrumentationType,
event_name: Option<FName>
);
impl ExInstrumentationEvent {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
let event_type: EScriptInstrumentationType =
EScriptInstrumentationType::try_from(asset.read_u8()?)?;
let mut event_name = None;
if event_type == EScriptInstrumentationType::InlineEvent {
event_name = Some(asset.read_fname()?);
}
Ok(ExInstrumentationEvent {
token: EExprToken::ExInstrumentationEvent,
event_type,
event_name,
})
}
}
impl KismetExpressionTrait for ExInstrumentationEvent {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_u8(self.event_type as u8)?;
if self.event_type == EScriptInstrumentationType::InlineEvent {
asset.write_fname(self.event_name.as_ref().ok_or_else(|| {
Error::no_data("event_type is InlineEvent but event_name is None".to_string())
})?)?;
return Ok(1 + 2 * size_of::<i32>());
}
Ok(1)
}
}
declare_expression!(
ExFloatConst,
#[container_ignore]
value: OrderedFloat<f32>
);
impl ExFloatConst {
pub fn new<Reader: ArchiveReader>(asset: &mut Reader) -> Result<Self, Error> {
Ok(ExFloatConst {
token: EExprToken::ExFloatConst,
value: OrderedFloat(asset.read_f32::<LE>()?),
})
}
}
impl KismetExpressionTrait for ExFloatConst {
fn write<Writer: ArchiveWriter>(&self, asset: &mut Writer) -> Result<usize, Error> {
asset.write_f32::<LE>(self.value.0)?;
Ok(size_of::<f32>())
}
}
implement_expression!(
ExBreakpoint,
ExDeprecatedOp4A,
ExEndArray,
ExEndArrayConst,
ExEndFunctionParms,
ExEndMap,
ExEndMapConst,
ExEndOfScript,
ExEndParmValue,
ExEndSet,
ExEndSetConst,
ExEndStructConst,
ExFalse,
ExIntOne,
ExIntZero,
ExNoInterface,
ExNoObject,
ExNothing,
ExPopExecutionFlow,
ExSelf,
ExTracepoint,
ExTrue,
ExWireTracepoint
);
implement_value_expression!(ExByteConst, u8, read_u8, write_u8);
implement_value_expression!(ExInt64Const, i64, read_i64, write_i64, LE);
implement_value_expression!(ExIntConst, i32, read_i32, write_i32, LE);
implement_value_expression!(ExIntConstByte, u8, read_u8, write_u8);
implement_value_expression!(ExSkipOffsetConst, u32, read_u32, write_u32, LE);
implement_value_expression!(ExUInt64Const, u64, read_u64, write_u64, LE);