diff --git a/api/SHIM-COVERAGE.md b/api/SHIM-COVERAGE.md index 603d29c..3bbd16b 100644 --- a/api/SHIM-COVERAGE.md +++ b/api/SHIM-COVERAGE.md @@ -4,7 +4,7 @@ Generated by `python3 tools/generate_api_shims.py`; do not edit by hand. | Assembly | Types | Members | Status | |---|---:|---:|---| -| `LibreMetaverse` | 2,711 | 27,281 | native implementation: 225 types / 15,463 members; remaining surface is callable failure-only shims | +| `LibreMetaverse` | 2,711 | 27,281 | native implementation: 237 types / 15,757 members; remaining surface is callable failure-only shims | | `LibreMetaverse.Imaging.Abstractions` | 3 | 20 | native implementation: 3 types / 20 members; no generated shims remain | | `LibreMetaverse.Imaging.Skia` | 1 | 3 | native implementation: 1 type / 3 members; no generated shims remain | | `LibreMetaverse.LslTools` | 164 | 768 | callable failure-only shim | diff --git a/crates/libremetaverse/src/avatar_animesh_semantics.rs b/crates/libremetaverse/src/avatar_animesh_semantics.rs index e782530..8db56f8 100644 --- a/crates/libremetaverse/src/avatar_animesh_semantics.rs +++ b/crates/libremetaverse/src/avatar_animesh_semantics.rs @@ -429,7 +429,7 @@ fn face(vertices: Vec, weights: Option>) -> Face { num_s: 0, num_t: 0, tex_coords1: None, - texture_face: PrimitiveTextureEntryFace, + texture_face: PrimitiveTextureEntryFace::default(), user_data: Object::from(""), vertices, weights, diff --git a/crates/libremetaverse/src/current_outfit.rs b/crates/libremetaverse/src/current_outfit.rs index 1fc78c9..629d313 100644 --- a/crates/libremetaverse/src/current_outfit.rs +++ b/crates/libremetaverse/src/current_outfit.rs @@ -1166,6 +1166,7 @@ pub(crate) fn primitive_defaults() -> Primitive { }, textures: None, tree_species: crate::Tree::Pine1, + unknown_extra_params: Vec::new(), velocity: libremetaverse_types::Vector3::zero(), } } diff --git a/crates/libremetaverse/src/generated.rs b/crates/libremetaverse/src/generated.rs index b4ef58b..673cc3b 100644 --- a/crates/libremetaverse/src/generated.rs +++ b/crates/libremetaverse/src/generated.rs @@ -10518,37 +10518,27 @@ impl Helpers { } /// C# member: `M:LibreMetaverse.Helpers.TEGlowByte(System.Single)`. pub fn te_glow_byte(glow: f32) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Helpers.TEGlowByte(System.Single)") + Ok(crate::object_model::te_glow_byte(glow)) } /// C# member: `M:LibreMetaverse.Helpers.TEGlowFloat(System.Byte[],System.Int32)`. pub fn te_glow_float(bytes: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Helpers.TEGlowFloat(System.Byte[],System.Int32)", - ) + crate::object_model::te_glow_float(bytes, pos) } /// C# member: `M:LibreMetaverse.Helpers.TEOffsetFloat(System.Byte[],System.Int32)`. pub fn te_offset_float(bytes: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Helpers.TEOffsetFloat(System.Byte[],System.Int32)", - ) + crate::object_model::te_offset_float(bytes, pos) } /// C# member: `M:LibreMetaverse.Helpers.TEOffsetShort(System.Single)`. pub fn te_offset_short(offset: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Helpers.TEOffsetShort(System.Single)", - ) + Ok(crate::object_model::te_offset_short(offset)) } /// C# member: `M:LibreMetaverse.Helpers.TERotationFloat(System.Byte[],System.Int32)`. pub fn te_rotation_float(bytes: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Helpers.TERotationFloat(System.Byte[],System.Int32)", - ) + crate::object_model::te_rotation_float(bytes, pos) } /// C# member: `M:LibreMetaverse.Helpers.TERotationShort(System.Single)`. pub fn te_rotation_short(rotation: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Helpers.TERotationShort(System.Single)", - ) + Ok(crate::object_model::te_rotation_short(rotation)) } /// C# member: `M:LibreMetaverse.Helpers.ZCompressOSD(LibreMetaverse.StructuredData.OSD)`. pub fn z_compress_osd( @@ -18290,765 +18280,236 @@ impl PrimEventArgs { } /// C# type: `T:LibreMetaverse.Primitive`. -pub struct Primitive { - /// C# member: `F:LibreMetaverse.Primitive.Acceleration`. - pub acceleration: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.ActiveClients`. - pub active_clients: i32, - /// C# member: `F:LibreMetaverse.Primitive.AngularVelocity`. - pub angular_velocity: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.CRC`. - pub crc: u32, - /// C# member: `F:LibreMetaverse.Primitive.ChildCount`. - pub child_count: i32, - /// C# member: `F:LibreMetaverse.Primitive.ClickAction`. - pub click_action: libremetaverse_types::ClickAction, - /// C# member: `F:LibreMetaverse.Primitive.CollisionPlane`. - pub collision_plane: libremetaverse_types::Vector4, - /// C# member: `F:LibreMetaverse.Primitive.ExtendedMeshFlags`. - pub extended_mesh_flags: u32, - /// C# member: `F:LibreMetaverse.Primitive.FaceMedia`. - pub face_media: Vec, - /// C# member: `F:LibreMetaverse.Primitive.Flags`. - pub flags: libremetaverse_types::PrimFlags, - /// C# member: `F:LibreMetaverse.Primitive.Flexible`. - pub flexible: Option, - /// C# member: `F:LibreMetaverse.Primitive.GroupID`. - pub group_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ID`. - pub id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.IsAttachment`. - pub is_attachment: bool, - /// C# member: `F:LibreMetaverse.Primitive.Joint`. - pub joint: libremetaverse_types::JointType, - /// C# member: `F:LibreMetaverse.Primitive.JointAxisOrAnchor`. - pub joint_axis_or_anchor: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.JointPivot`. - pub joint_pivot: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.Light`. - pub light: Option, - /// C# member: `F:LibreMetaverse.Primitive.LightMap`. - pub light_map: Option, - /// C# member: `F:LibreMetaverse.Primitive.LocalID`. - pub local_id: u32, - /// C# member: `F:LibreMetaverse.Primitive.MediaURL`. - pub media_url: String, - /// C# member: `F:LibreMetaverse.Primitive.MediaVersion`. - pub media_version: String, - /// C# member: `F:LibreMetaverse.Primitive.NameValues`. - pub name_values: Option>, - /// C# member: `F:LibreMetaverse.Primitive.OwnerID`. - pub owner_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ParentID`. - pub parent_id: u32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSys`. - pub particle_sys: libremetaverse::PrimitiveParticleSystem, - /// C# member: `F:LibreMetaverse.Primitive.PhysicsProps`. - pub physics_props: Option, - /// C# member: `F:LibreMetaverse.Primitive.Position`. - pub position: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.PrimData`. - pub prim_data: libremetaverse::PrimitiveConstructionData, - /// C# member: `F:LibreMetaverse.Primitive.Properties`. - pub properties: Option, - /// C# member: `F:LibreMetaverse.Primitive.RegionHandle`. - pub region_handle: u64, - /// C# member: `F:LibreMetaverse.Primitive.Rotation`. - pub rotation: libremetaverse_types::Quaternion, - /// C# member: `F:LibreMetaverse.Primitive.Scale`. - pub scale: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.ScratchPad`. - pub scratch_pad: Vec, - /// C# member: `F:LibreMetaverse.Primitive.Sculpt`. - pub sculpt: Option, - /// C# member: `F:LibreMetaverse.Primitive.SignaledAnimations`. - pub signaled_animations: Option>, - /// C# member: `F:LibreMetaverse.Primitive.Sound`. - pub sound: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.SoundFlags`. - pub sound_flags: libremetaverse_types::SoundFlags, - /// C# member: `F:LibreMetaverse.Primitive.SoundGain`. - pub sound_gain: f32, - /// C# member: `F:LibreMetaverse.Primitive.SoundRadius`. - pub sound_radius: f32, - /// C# member: `F:LibreMetaverse.Primitive.Tag`. - pub tag: Option, - /// C# member: `F:LibreMetaverse.Primitive.Text`. - pub text: String, - /// C# member: `F:LibreMetaverse.Primitive.TextColor`. - pub text_color: libremetaverse_types::Color4, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnim`. - pub texture_anim: libremetaverse::PrimitiveTextureAnimation, - /// C# member: `F:LibreMetaverse.Primitive.Textures`. - pub textures: Option, - /// C# member: `F:LibreMetaverse.Primitive.TreeSpecies`. - pub tree_species: libremetaverse::Tree, - /// C# member: `F:LibreMetaverse.Primitive.Velocity`. - pub velocity: libremetaverse_types::Vector3, -} -impl Primitive { - /// C# member: `M:LibreMetaverse.Primitive.#ctor`. - pub fn new_with_constructor() -> Result { - Ok(crate::current_outfit::primitive_defaults()) - } - /// C# member: `M:LibreMetaverse.Primitive.#ctor(LibreMetaverse.Primitive)`. - pub fn new_with_primitive(prim: libremetaverse::Primitive) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.#ctor(LibreMetaverse.Primitive)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.Equals(LibreMetaverse.Primitive)`. - pub fn equals_with_primitive(&self, other: Option) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.Equals(LibreMetaverse.Primitive)" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.Equals(System.Object)`. - pub fn equals_with_object(&self, obj: Option) -> bool { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.Equals(System.Object)") - } - /// C# member: `M:LibreMetaverse.Primitive.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.GetChildren(LibreMetaverse.GridClient)`. - pub fn get_children( - &self, - client: libremetaverse::GridClient, - ) -> Result>, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.GetChildren(LibreMetaverse.GridClient)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.GetExtraParamsBytes`. - pub fn get_extra_params_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.GetExtraParamsBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.GetGrassDefinition`. - pub fn get_grass_definition(&self) -> Result { - crate::foliage_catalog::grass_by_id(self.prim_data.state) - } - /// C# member: `M:LibreMetaverse.Primitive.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.GetHashCode") - } - /// C# member: `M:LibreMetaverse.Primitive.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.GetOSD") - } - /// C# member: `M:LibreMetaverse.Primitive.GetTreeDefinition`. - pub fn get_tree_definition(&self) -> Result { - crate::foliage_catalog::TreeDefinitions::get(self.tree_species) - } - /// C# member: `M:LibreMetaverse.Primitive.PackBeginCut(System.Single)`. - pub fn pack_begin_cut(begin_cut: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackBeginCut(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackEndCut(System.Single)`. - pub fn pack_end_cut(end_cut: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackEndCut(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackPathRevolutions(System.Single)`. - pub fn pack_path_revolutions(path_revolutions: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackPathRevolutions(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackPathScale(System.Single)`. - pub fn pack_path_scale(path_scale: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackPathScale(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackPathShear(System.Single)`. - pub fn pack_path_shear(path_shear: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackPathShear(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackPathTaper(System.Single)`. - pub fn pack_path_taper(path_taper: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackPathTaper(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackPathTwist(System.Single)`. - pub fn pack_path_twist(path_twist: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackPathTwist(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.PackProfileHollow(System.Single)`. - pub fn pack_profile_hollow(profile_hollow: f32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.PackProfileHollow(System.Single)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.SetExtraParamsFromBytes(System.Byte[],System.Int32)`. - pub fn set_extra_params_from_bytes( - &self, - data: Vec, - pos: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.SetExtraParamsFromBytes(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.ToString") - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackBeginCut(System.UInt16)`. - pub fn unpack_begin_cut(begin_cut: u16) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackBeginCut(System.UInt16)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackEndCut(System.UInt16)`. - pub fn unpack_end_cut(end_cut: u16) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackEndCut(System.UInt16)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackPathRevolutions(System.Byte)`. - pub fn unpack_path_revolutions(path_revolutions: u8) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackPathRevolutions(System.Byte)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackPathScale(System.Byte)`. - pub fn unpack_path_scale(path_scale: u8) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackPathScale(System.Byte)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackPathShear(System.SByte)`. - pub fn unpack_path_shear(path_shear: i8) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackPathShear(System.SByte)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackPathTaper(System.SByte)`. - pub fn unpack_path_taper(path_taper: i8) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackPathTaper(System.SByte)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackPathTwist(System.SByte)`. - pub fn unpack_path_twist(path_twist: i8) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackPathTwist(System.SByte)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.UnpackProfileHollow(System.UInt16)`. - pub fn unpack_profile_hollow(profile_hollow: u16) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.UnpackProfileHollow(System.UInt16)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.op_Equality(LibreMetaverse.Primitive,LibreMetaverse.Primitive)`. - pub fn eq( - lhs: Option, - rhs: Option, - ) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.op_Equality(LibreMetaverse.Primitive,LibreMetaverse.Primitive)" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.op_Inequality(LibreMetaverse.Primitive,LibreMetaverse.Primitive)`. - pub fn ne( - lhs: Option, - rhs: Option, - ) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.op_Inequality(LibreMetaverse.Primitive,LibreMetaverse.Primitive)" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.GrassSpecies`. - pub fn grass_species(&self) -> libremetaverse::Grass { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.GrassSpecies") - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.GrassSpecies`. - pub fn set_grass_species(&mut self, value: libremetaverse::Grass) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.GrassSpecies") - } - /// C# member: `P:LibreMetaverse.Primitive.IsAnimatedObject`. - pub fn is_animated_object(&self) -> bool { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.IsAnimatedObject") - } - /// C# member: `P:LibreMetaverse.Primitive.Type`. - pub fn type_(&self) -> libremetaverse_types::PrimType { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.Type") - } -} +/// C# member: `F:LibreMetaverse.Primitive.Acceleration`. +/// C# member: `F:LibreMetaverse.Primitive.ActiveClients`. +/// C# member: `F:LibreMetaverse.Primitive.AngularVelocity`. +/// C# member: `F:LibreMetaverse.Primitive.CRC`. +/// C# member: `F:LibreMetaverse.Primitive.ChildCount`. +/// C# member: `F:LibreMetaverse.Primitive.ClickAction`. +/// C# member: `F:LibreMetaverse.Primitive.CollisionPlane`. +/// C# member: `F:LibreMetaverse.Primitive.ExtendedMeshFlags`. +/// C# member: `F:LibreMetaverse.Primitive.FaceMedia`. +/// C# member: `F:LibreMetaverse.Primitive.Flags`. +/// C# member: `F:LibreMetaverse.Primitive.Flexible`. +/// C# member: `F:LibreMetaverse.Primitive.GroupID`. +/// C# member: `F:LibreMetaverse.Primitive.ID`. +/// C# member: `F:LibreMetaverse.Primitive.IsAttachment`. +/// C# member: `F:LibreMetaverse.Primitive.Joint`. +/// C# member: `F:LibreMetaverse.Primitive.JointAxisOrAnchor`. +/// C# member: `F:LibreMetaverse.Primitive.JointPivot`. +/// C# member: `F:LibreMetaverse.Primitive.Light`. +/// C# member: `F:LibreMetaverse.Primitive.LightMap`. +/// C# member: `F:LibreMetaverse.Primitive.LocalID`. +/// C# member: `F:LibreMetaverse.Primitive.MediaURL`. +/// C# member: `F:LibreMetaverse.Primitive.MediaVersion`. +/// C# member: `F:LibreMetaverse.Primitive.NameValues`. +/// C# member: `F:LibreMetaverse.Primitive.OwnerID`. +/// C# member: `F:LibreMetaverse.Primitive.ParentID`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSys`. +/// C# member: `F:LibreMetaverse.Primitive.PhysicsProps`. +/// C# member: `F:LibreMetaverse.Primitive.Position`. +/// C# member: `F:LibreMetaverse.Primitive.PrimData`. +/// C# member: `F:LibreMetaverse.Primitive.Properties`. +/// C# member: `F:LibreMetaverse.Primitive.RegionHandle`. +/// C# member: `F:LibreMetaverse.Primitive.Rotation`. +/// C# member: `F:LibreMetaverse.Primitive.Scale`. +/// C# member: `F:LibreMetaverse.Primitive.ScratchPad`. +/// C# member: `F:LibreMetaverse.Primitive.Sculpt`. +/// C# member: `F:LibreMetaverse.Primitive.SignaledAnimations`. +/// C# member: `F:LibreMetaverse.Primitive.Sound`. +/// C# member: `F:LibreMetaverse.Primitive.SoundFlags`. +/// C# member: `F:LibreMetaverse.Primitive.SoundGain`. +/// C# member: `F:LibreMetaverse.Primitive.SoundRadius`. +/// C# member: `F:LibreMetaverse.Primitive.Tag`. +/// C# member: `F:LibreMetaverse.Primitive.Text`. +/// C# member: `F:LibreMetaverse.Primitive.TextColor`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnim`. +/// C# member: `F:LibreMetaverse.Primitive.Textures`. +/// C# member: `F:LibreMetaverse.Primitive.TreeSpecies`. +/// C# member: `F:LibreMetaverse.Primitive.Velocity`. +/// C# member: `M:LibreMetaverse.Primitive.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.#ctor(LibreMetaverse.Primitive)`. +/// C# member: `M:LibreMetaverse.Primitive.Equals(LibreMetaverse.Primitive)`. +/// C# member: `M:LibreMetaverse.Primitive.Equals(System.Object)`. +/// C# member: `M:LibreMetaverse.Primitive.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.GetChildren(LibreMetaverse.GridClient)`. +/// C# member: `M:LibreMetaverse.Primitive.GetExtraParamsBytes`. +/// C# member: `M:LibreMetaverse.Primitive.GetGrassDefinition`. +/// C# member: `M:LibreMetaverse.Primitive.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.GetOSD`. +/// C# member: `M:LibreMetaverse.Primitive.GetTreeDefinition`. +/// C# member: `M:LibreMetaverse.Primitive.PackBeginCut(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackEndCut(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackPathRevolutions(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackPathScale(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackPathShear(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackPathTaper(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackPathTwist(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.PackProfileHollow(System.Single)`. +/// C# member: `M:LibreMetaverse.Primitive.SetExtraParamsFromBytes(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.ToString`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackBeginCut(System.UInt16)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackEndCut(System.UInt16)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackPathRevolutions(System.Byte)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackPathScale(System.Byte)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackPathShear(System.SByte)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackPathTaper(System.SByte)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackPathTwist(System.SByte)`. +/// C# member: `M:LibreMetaverse.Primitive.UnpackProfileHollow(System.UInt16)`. +/// C# member: `M:LibreMetaverse.Primitive.op_Equality(LibreMetaverse.Primitive,LibreMetaverse.Primitive)`. +/// C# member: `M:LibreMetaverse.Primitive.op_Inequality(LibreMetaverse.Primitive,LibreMetaverse.Primitive)`. +/// C# member: `P:LibreMetaverse.Primitive.GrassSpecies`. +/// C# member: `P:LibreMetaverse.Primitive.IsAnimatedObject`. +/// C# member: `P:LibreMetaverse.Primitive.Type`. +pub use crate::object_model::Primitive; /// C# type: `T:LibreMetaverse.Primitive.ConstructionData`. -pub struct PrimitiveConstructionData { - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.Material`. - pub material: libremetaverse_types::Material, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PCode`. - pub p_code: libremetaverse_types::PCode, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathBegin`. - pub path_begin: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathCurve`. - pub path_curve: libremetaverse_types::PathCurve, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathEnd`. - pub path_end: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathRadiusOffset`. - pub path_radius_offset: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathRevolutions`. - pub path_revolutions: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathScaleX`. - pub path_scale_x: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathScaleY`. - pub path_scale_y: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathShearX`. - pub path_shear_x: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathShearY`. - pub path_shear_y: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathSkew`. - pub path_skew: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTaperX`. - pub path_taper_x: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTaperY`. - pub path_taper_y: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTwist`. - pub path_twist: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTwistBegin`. - pub path_twist_begin: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.ProfileBegin`. - pub profile_begin: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.ProfileEnd`. - pub profile_end: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.ProfileHollow`. - pub profile_hollow: f32, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.State`. - pub state: u8, - /// C# member: `F:LibreMetaverse.Primitive.ConstructionData.profileCurve`. - pub profile_curve_with_field: u8, -} -impl PrimitiveConstructionData { - /// C# member: `M:LibreMetaverse.Primitive.ConstructionData.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.ConstructionData.#ctor") - } - /// C# member: `M:LibreMetaverse.Primitive.ConstructionData.#ctor(LibreMetaverse.Primitive.ConstructionData)`. - pub fn new_with_construction_data( - other: libremetaverse::PrimitiveConstructionData, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ConstructionData.#ctor(LibreMetaverse.Primitive.ConstructionData)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ConstructionData.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.ConstructionData.GetHashCode" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.ConstructionData.AttachmentPoint`. - pub fn attachment_point(&self) -> libremetaverse_types::AttachmentPoint { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.AttachmentPoint" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.ConstructionData.AttachmentPoint`. - pub fn set_attachment_point(&mut self, value: libremetaverse_types::AttachmentPoint) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.AttachmentPoint" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.ConstructionData.PathBeginScale`. - pub fn path_begin_scale(&self) -> libremetaverse_types::Vector2 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.PathBeginScale" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.ConstructionData.PathEndScale`. - pub fn path_end_scale(&self) -> libremetaverse_types::Vector2 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.PathEndScale" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.ConstructionData.ProfileCurve`. - pub fn profile_curve_with_property(&self) -> libremetaverse_types::ProfileCurve { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.ProfileCurve" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.ConstructionData.ProfileCurve`. - pub fn set_profile_curve_with_property(&mut self, value: libremetaverse_types::ProfileCurve) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.ProfileCurve" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.ConstructionData.ProfileHole`. - pub fn profile_hole(&self) -> libremetaverse_types::HoleType { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.ProfileHole" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.ConstructionData.ProfileHole`. - pub fn set_profile_hole(&mut self, value: libremetaverse_types::HoleType) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.ConstructionData.ProfileHole" - ) - } -} +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.Material`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PCode`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathBegin`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathCurve`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathEnd`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathRadiusOffset`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathRevolutions`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathScaleX`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathScaleY`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathShearX`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathShearY`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathSkew`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTaperX`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTaperY`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTwist`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.PathTwistBegin`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.ProfileBegin`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.ProfileEnd`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.ProfileHollow`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.State`. +/// C# member: `F:LibreMetaverse.Primitive.ConstructionData.profileCurve`. +/// C# member: `M:LibreMetaverse.Primitive.ConstructionData.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.ConstructionData.#ctor(LibreMetaverse.Primitive.ConstructionData)`. +/// C# member: `M:LibreMetaverse.Primitive.ConstructionData.GetHashCode`. +/// C# member: `P:LibreMetaverse.Primitive.ConstructionData.AttachmentPoint`. +/// C# member: `P:LibreMetaverse.Primitive.ConstructionData.PathBeginScale`. +/// C# member: `P:LibreMetaverse.Primitive.ConstructionData.PathEndScale`. +/// C# member: `P:LibreMetaverse.Primitive.ConstructionData.ProfileCurve`. +/// C# member: `P:LibreMetaverse.Primitive.ConstructionData.ProfileHole`. +pub use crate::object_model::PrimitiveConstructionData; /// C# type: `T:LibreMetaverse.Primitive.FlexibleData`. -pub struct PrimitiveFlexibleData { - /// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Drag`. - pub drag: f32, - /// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Force`. - pub force: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Gravity`. - pub gravity: f32, - /// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Softness`. - pub softness: i32, - /// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Tension`. - pub tension: f32, - /// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Wind`. - pub wind: f32, -} -impl PrimitiveFlexibleData { - /// C# member: `M:LibreMetaverse.Primitive.FlexibleData.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.FlexibleData.#ctor") - } - /// C# member: `M:LibreMetaverse.Primitive.FlexibleData.#ctor(System.Byte[],System.Int32)`. - pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.FlexibleData.#ctor(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.FlexibleData.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.FlexibleData.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.FlexibleData.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.FlexibleData.GetBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.FlexibleData.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.FlexibleData.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.FlexibleData.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.FlexibleData.GetOSD") - } -} +/// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Drag`. +/// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Force`. +/// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Gravity`. +/// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Softness`. +/// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Tension`. +/// C# member: `F:LibreMetaverse.Primitive.FlexibleData.Wind`. +/// C# member: `M:LibreMetaverse.Primitive.FlexibleData.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.FlexibleData.#ctor(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.FlexibleData.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.FlexibleData.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.FlexibleData.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.FlexibleData.GetOSD`. +pub use crate::object_model::PrimitiveFlexibleData; /// C# type: `T:LibreMetaverse.Primitive.LightData`. -pub struct PrimitiveLightData { - /// C# member: `F:LibreMetaverse.Primitive.LightData.Color`. - pub color: libremetaverse_types::Color4, - /// C# member: `F:LibreMetaverse.Primitive.LightData.Cutoff`. - pub cutoff: f32, - /// C# member: `F:LibreMetaverse.Primitive.LightData.Falloff`. - pub falloff: f32, - /// C# member: `F:LibreMetaverse.Primitive.LightData.Intensity`. - pub intensity: f32, - /// C# member: `F:LibreMetaverse.Primitive.LightData.Radius`. - pub radius: f32, -} -impl PrimitiveLightData { - /// C# member: `M:LibreMetaverse.Primitive.LightData.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.LightData.#ctor") - } - /// C# member: `M:LibreMetaverse.Primitive.LightData.#ctor(System.Byte[],System.Int32)`. - pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.LightData.#ctor(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.LightData.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.LightData.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.LightData.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.LightData.GetBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.LightData.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.LightData.GetHashCode") - } - /// C# member: `M:LibreMetaverse.Primitive.LightData.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.LightData.GetOSD") - } - /// C# member: `M:LibreMetaverse.Primitive.LightData.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.LightData.ToString") - } -} +/// C# member: `F:LibreMetaverse.Primitive.LightData.Color`. +/// C# member: `F:LibreMetaverse.Primitive.LightData.Cutoff`. +/// C# member: `F:LibreMetaverse.Primitive.LightData.Falloff`. +/// C# member: `F:LibreMetaverse.Primitive.LightData.Intensity`. +/// C# member: `F:LibreMetaverse.Primitive.LightData.Radius`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.#ctor(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.GetOSD`. +/// C# member: `M:LibreMetaverse.Primitive.LightData.ToString`. +pub use crate::object_model::PrimitiveLightData; /// C# type: `T:LibreMetaverse.Primitive.LightImage`. -pub struct PrimitiveLightImage { - /// C# member: `F:LibreMetaverse.Primitive.LightImage.LightTexture`. - pub light_texture: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.LightImage.Params`. - pub params: libremetaverse_types::Vector3, -} -impl PrimitiveLightImage { - /// C# member: `M:LibreMetaverse.Primitive.LightImage.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.LightImage.#ctor") - } - /// C# member: `M:LibreMetaverse.Primitive.LightImage.#ctor(System.Byte[],System.Int32)`. - pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.LightImage.#ctor(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.LightImage.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.LightImage.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.LightImage.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.LightImage.GetBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.LightImage.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.LightImage.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.LightImage.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.LightImage.GetOSD") - } - /// C# member: `M:LibreMetaverse.Primitive.LightImage.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.LightImage.ToString") - } -} +/// C# member: `F:LibreMetaverse.Primitive.LightImage.LightTexture`. +/// C# member: `F:LibreMetaverse.Primitive.LightImage.Params`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.#ctor(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.GetOSD`. +/// C# member: `M:LibreMetaverse.Primitive.LightImage.ToString`. +pub use crate::object_model::PrimitiveLightImage; /// C# type: `T:LibreMetaverse.Primitive.ObjectProperties`. -pub struct PrimitiveObjectProperties { - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.AggregatePermTextures`. - pub aggregate_perm_textures: u8, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.AggregatePermTexturesOwner`. - pub aggregate_perm_textures_owner: u8, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.AggregatePerms`. - pub aggregate_perms: u8, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Category`. - pub category: libremetaverse_types::ObjectCategory, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.CreationDate`. - pub creation_date: std::time::SystemTime, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.CreatorID`. - pub creator_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Description`. - pub description: String, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.FolderID`. - pub folder_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.FromTaskID`. - pub from_task_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.GroupID`. - pub group_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.InventorySerial`. - pub inventory_serial: i16, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.ItemID`. - pub item_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.LastOwnerID`. - pub last_owner_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Name`. - pub name: String, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.ObjectID`. - pub object_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.OwnerID`. - pub owner_id: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.OwnershipCost`. - pub ownership_cost: i32, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Permissions`. - pub permissions: libremetaverse::Permissions, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.SalePrice`. - pub sale_price: i32, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.SaleType`. - pub sale_type: libremetaverse_types::SaleType, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.SitName`. - pub sit_name: String, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.TextureIDs`. - pub texture_i_ds: Vec, - /// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.TouchName`. - pub touch_name: String, -} -impl PrimitiveObjectProperties { - /// C# member: `M:LibreMetaverse.Primitive.ObjectProperties.#ctor`. - pub fn new() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.ObjectProperties.#ctor") - } - /// C# member: `M:LibreMetaverse.Primitive.ObjectProperties.GetTextureIDBytes`. - pub fn get_texture_id_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ObjectProperties.GetTextureIDBytes", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ObjectProperties.SetFamilyProperties(LibreMetaverse.Primitive.ObjectProperties)`. - pub fn set_family_properties( - &self, - props: libremetaverse::PrimitiveObjectProperties, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ObjectProperties.SetFamilyProperties(LibreMetaverse.Primitive.ObjectProperties)", - ) - } -} +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.AggregatePermTextures`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.AggregatePermTexturesOwner`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.AggregatePerms`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Category`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.CreationDate`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.CreatorID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Description`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.FolderID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.FromTaskID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.GroupID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.InventorySerial`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.ItemID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.LastOwnerID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Name`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.ObjectID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.OwnerID`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.OwnershipCost`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.Permissions`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.SalePrice`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.SaleType`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.SitName`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.TextureIDs`. +/// C# member: `F:LibreMetaverse.Primitive.ObjectProperties.TouchName`. +/// C# member: `M:LibreMetaverse.Primitive.ObjectProperties.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.ObjectProperties.GetTextureIDBytes`. +/// C# member: `M:LibreMetaverse.Primitive.ObjectProperties.SetFamilyProperties(LibreMetaverse.Primitive.ObjectProperties)`. +pub use crate::object_model::PrimitiveObjectProperties; /// C# type: `T:LibreMetaverse.Primitive.ParticleSystem`. -pub struct PrimitiveParticleSystem { - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.AngularVelocity`. - pub angular_velocity: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BlendFuncDest`. - pub blend_func_dest: u8, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BlendFuncSource`. - pub blend_func_source: u8, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstPartCount`. - pub burst_part_count: u8, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstRadius`. - pub burst_radius: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstRate`. - pub burst_rate: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstSpeedMax`. - pub burst_speed_max: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstSpeedMin`. - pub burst_speed_min: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.CRC`. - pub crc: u32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.InnerAngle`. - pub inner_angle: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.MaxAge`. - pub max_age: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.OuterAngle`. - pub outer_angle: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartAcceleration`. - pub part_acceleration: libremetaverse_types::Vector3, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartDataFlags`. - pub part_data_flags: libremetaverse::PrimitiveParticleSystemParticleDataFlags, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndColor`. - pub part_end_color: libremetaverse_types::Color4, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndGlow`. - pub part_end_glow: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndScaleX`. - pub part_end_scale_x: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndScaleY`. - pub part_end_scale_y: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartFlags`. - pub part_flags: u32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartMaxAge`. - pub part_max_age: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartColor`. - pub part_start_color: libremetaverse_types::Color4, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartGlow`. - pub part_start_glow: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartScaleX`. - pub part_start_scale_x: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartScaleY`. - pub part_start_scale_y: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.Pattern`. - pub pattern: libremetaverse::PrimitiveParticleSystemSourcePattern, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.StartAge`. - pub start_age: f32, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.Target`. - pub target: libremetaverse_types::UUID, - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.Texture`. - pub texture: libremetaverse_types::UUID, -} -impl PrimitiveParticleSystem { - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.LegacyDataBlockSize`. - pub const LEGACY_DATA_BLOCK_SIZE: u8 = 86; - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.MaxDataBlockSize`. - pub const MAX_DATA_BLOCK_SIZE: u8 = 98; - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartDataSize`. - pub const PART_DATA_SIZE: u8 = 18; - /// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.SysDataSize`. - pub const SYS_DATA_SIZE: u8 = 68; - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.#ctor(System.Byte[],System.Int32)`. - pub fn new(data: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ParticleSystem.#ctor(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.Equals(LibreMetaverse.Primitive.ParticleSystem)`. - pub fn equals_with_particle_system( - &self, - other: libremetaverse::PrimitiveParticleSystem, - ) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.ParticleSystem.Equals(LibreMetaverse.Primitive.ParticleSystem)" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.Equals(System.Object)`. - pub fn equals_with_object(&self, obj: Option) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.ParticleSystem.Equals(System.Object)" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ParticleSystem.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.ParticleSystem.GetBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.ParticleSystem.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.ParticleSystem.GetOSD") - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.HasBlendFunc`. - pub fn has_blend_func(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ParticleSystem.HasBlendFunc", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.HasGlow`. - pub fn has_glow(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.ParticleSystem.HasGlow") - } - /// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.IsLegacyCompatible`. - pub fn is_legacy_compatible(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.ParticleSystem.IsLegacyCompatible", - ) - } -} +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.AngularVelocity`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BlendFuncDest`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BlendFuncSource`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstPartCount`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstRadius`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstRate`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstSpeedMax`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.BurstSpeedMin`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.CRC`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.InnerAngle`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.LegacyDataBlockSize`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.MaxAge`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.MaxDataBlockSize`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.OuterAngle`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartAcceleration`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartDataFlags`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartDataSize`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndColor`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndGlow`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndScaleX`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartEndScaleY`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartFlags`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartMaxAge`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartColor`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartGlow`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartScaleX`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.PartStartScaleY`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.Pattern`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.StartAge`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.SysDataSize`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.Target`. +/// C# member: `F:LibreMetaverse.Primitive.ParticleSystem.Texture`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.#ctor(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.Equals(LibreMetaverse.Primitive.ParticleSystem)`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.Equals(System.Object)`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.GetOSD`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.HasBlendFunc`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.HasGlow`. +/// C# member: `M:LibreMetaverse.Primitive.ParticleSystem.IsLegacyCompatible`. +pub use crate::object_model::PrimitiveParticleSystem; /// C# type: `T:LibreMetaverse.Primitive.ParticleSystem.BlendFunc`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -19156,60 +18617,17 @@ impl PrimitiveParticleSystemSourcePattern { pub use crate::message_decoder::PrimitivePhysicsProperties; /// C# type: `T:LibreMetaverse.Primitive.SculptData`. -pub struct PrimitiveSculptData { - /// C# member: `F:LibreMetaverse.Primitive.SculptData.SculptTexture`. - pub sculpt_texture: libremetaverse_types::UUID, -} -impl PrimitiveSculptData { - /// C# member: `M:LibreMetaverse.Primitive.SculptData.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.SculptData.#ctor") - } - /// C# member: `M:LibreMetaverse.Primitive.SculptData.#ctor(System.Byte[],System.Int32)`. - pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.SculptData.#ctor(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.SculptData.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.SculptData.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.SculptData.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.SculptData.GetBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.SculptData.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.SculptData.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.SculptData.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.SculptData.GetOSD") - } - /// C# member: `P:LibreMetaverse.Primitive.SculptData.Invert`. - pub fn invert(&self) -> bool { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.SculptData.Invert") - } - /// C# member: `P:LibreMetaverse.Primitive.SculptData.Mirror`. - pub fn mirror(&self) -> bool { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.SculptData.Mirror") - } - /// C# member: `P:LibreMetaverse.Primitive.SculptData.Type`. - pub fn type_(&self) -> libremetaverse_types::SculptType { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.SculptData.Type") - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.SculptData.Type`. - pub fn set_type_(&mut self, value: libremetaverse_types::SculptType) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.SculptData.Type") - } -} +/// C# member: `F:LibreMetaverse.Primitive.SculptData.SculptTexture`. +/// C# member: `M:LibreMetaverse.Primitive.SculptData.#ctor`. +/// C# member: `M:LibreMetaverse.Primitive.SculptData.#ctor(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.SculptData.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.SculptData.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.SculptData.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.SculptData.GetOSD`. +/// C# member: `P:LibreMetaverse.Primitive.SculptData.Invert`. +/// C# member: `P:LibreMetaverse.Primitive.SculptData.Mirror`. +/// C# member: `P:LibreMetaverse.Primitive.SculptData.Type`. +pub use crate::object_model::PrimitiveSculptData; /// C# type: `T:LibreMetaverse.Primitive.TextureAnimMode`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -19235,385 +18653,64 @@ impl PrimitiveTextureAnimMode { } /// C# type: `T:LibreMetaverse.Primitive.TextureAnimation`. -pub struct PrimitiveTextureAnimation { - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Face`. - pub face: u32, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Flags`. - pub flags: libremetaverse::PrimitiveTextureAnimMode, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Length`. - pub length: f32, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Rate`. - pub rate: f32, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.SizeX`. - pub size_x: u32, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.SizeY`. - pub size_y: u32, - /// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Start`. - pub start: f32, -} -impl PrimitiveTextureAnimation { - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.#ctor(System.Byte[],System.Int32)`. - pub fn new(data: Vec, pos: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureAnimation.#ctor(System.Byte[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.Equals(LibreMetaverse.Primitive.TextureAnimation)`. - pub fn equals_with_texture_animation( - &self, - other: libremetaverse::PrimitiveTextureAnimation, - ) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.TextureAnimation.Equals(LibreMetaverse.Primitive.TextureAnimation)" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.Equals(System.Object)`. - pub fn equals_with_object(&self, obj: Option) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.TextureAnimation.Equals(System.Object)" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureAnimation.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureAnimation.GetBytes", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.TextureAnimation.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.TextureAnimation.GetOSD") - } -} +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Face`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Flags`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Length`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Rate`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.SizeX`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.SizeY`. +/// C# member: `F:LibreMetaverse.Primitive.TextureAnimation.Start`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.#ctor(System.Byte[],System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.Equals(LibreMetaverse.Primitive.TextureAnimation)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.Equals(System.Object)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.TextureAnimation.GetOSD`. +pub use crate::object_model::PrimitiveTextureAnimation; /// C# type: `T:LibreMetaverse.Primitive.TextureEntry`. -pub struct PrimitiveTextureEntry { - /// C# member: `F:LibreMetaverse.Primitive.TextureEntry.DefaultTexture`. - pub default_texture: Option, - /// C# member: `F:LibreMetaverse.Primitive.TextureEntry.FaceTextures`. - pub face_textures: Vec>, -} -impl PrimitiveTextureEntry { - /// C# member: `F:LibreMetaverse.Primitive.TextureEntry.MAX_FACES`. - pub const MAX_FACES: i32 = 45; - /// C# member: `F:LibreMetaverse.Primitive.TextureEntry.WHITE_TEXTURE`. - pub fn white_texture() -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!( - "F:LibreMetaverse.Primitive.TextureEntry.WHITE_TEXTURE" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.Primitive.TextureEntry)`. - pub fn new_with_texture_entry( - source: libremetaverse::PrimitiveTextureEntry, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.Primitive.TextureEntry)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.Primitive.TextureEntryFace)`. - pub fn new_with_texture_entry_face( - default_face: libremetaverse::PrimitiveTextureEntryFace, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.Primitive.TextureEntryFace)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.UUID)`. - pub fn new_with_uuid( - default_texture_id: libremetaverse_types::UUID, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.UUID)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(System.Byte[],System.Int32,System.Int32)`. - pub fn new_with_bytes_int32_int32( - data: Vec, - pos: i32, - length: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.#ctor(System.Byte[],System.Int32,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.CreateFace(System.UInt32)`. - pub fn create_face( - &mut self, - index: u32, - ) -> Result<&mut libremetaverse::PrimitiveTextureEntryFace, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.CreateFace(System.UInt32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.FromOSD(LibreMetaverse.StructuredData.OSD)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.FromOSD(LibreMetaverse.StructuredData.OSD)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetBytes`. - pub fn get_bytes(&self) -> Result, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.TextureEntry.GetBytes") - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetFace(System.UInt32)`. - pub fn get_face( - &self, - index: u32, - ) -> Result, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntry.GetFace(System.UInt32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.TextureEntry.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetOSD`. - pub fn get_osd(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.TextureEntry.GetOSD") - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntry.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!("M:LibreMetaverse.Primitive.TextureEntry.ToString") - } -} +/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.DefaultTexture`. +/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.FaceTextures`. +/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.MAX_FACES`. +/// C# member: `F:LibreMetaverse.Primitive.TextureEntry.WHITE_TEXTURE`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.Primitive.TextureEntry)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.Primitive.TextureEntryFace)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(LibreMetaverse.UUID)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.#ctor(System.Byte[],System.Int32,System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.CreateFace(System.UInt32)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.FromOSD(LibreMetaverse.StructuredData.OSD)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetBytes`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetFace(System.UInt32)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.GetOSD`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntry.ToString`. +pub use crate::object_model::PrimitiveTextureEntry; /// C# type: `T:LibreMetaverse.Primitive.TextureEntryFace`. -pub struct PrimitiveTextureEntryFace; -impl PrimitiveTextureEntryFace { - /// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.#ctor(LibreMetaverse.Primitive.TextureEntryFace)`. - pub fn new( - default_texture: Option, - ) -> Result { - crate::visual_catalog::new_texture_entry_face() - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.Clone`. - pub fn clone(&self) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.TextureEntryFace.Clone") - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.FromOSD(LibreMetaverse.StructuredData.OSD,LibreMetaverse.Primitive.TextureEntryFace,System.Int32@)`. - pub fn from_osd( - osd: libremetaverse_structured_data::OSD, - default_face: Option, - face_number: &mut i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntryFace.FromOSD(LibreMetaverse.StructuredData.OSD,LibreMetaverse.Primitive.TextureEntryFace,System.Int32@)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.GetHashCode`. - pub fn get_hash_code(&self) -> i32 { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.TextureEntryFace.GetHashCode" - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.GetOSD(System.Int32)`. - pub fn get_osd( - &self, - face_number: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Primitive.TextureEntryFace.GetOSD(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.ToString`. - pub fn to_string(&self) -> String { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.Primitive.TextureEntryFace.ToString" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Bump`. - pub fn bump(&self) -> libremetaverse::Bumpiness { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.TextureEntryFace.Bump") - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Bump`. - pub fn set_bump(&mut self, value: libremetaverse::Bumpiness) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.TextureEntryFace.Bump") - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Fullbright`. - pub fn fullbright(&self) -> bool { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Fullbright" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Fullbright`. - pub fn set_fullbright(&mut self, value: bool) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Fullbright" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Glow`. - pub fn glow(&self) -> f32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.TextureEntryFace.Glow") - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Glow`. - pub fn set_glow(&mut self, value: f32) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.TextureEntryFace.Glow") - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.MaterialID`. - pub fn material_id(&self) -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.MaterialID" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.MaterialID`. - pub fn set_material_id(&mut self, value: libremetaverse_types::UUID) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.MaterialID" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.MediaFlags`. - pub fn media_flags(&self) -> bool { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.MediaFlags" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.MediaFlags`. - pub fn set_media_flags(&mut self, value: bool) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.MediaFlags" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.OffsetU`. - pub fn offset_u(&self) -> f32 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.OffsetU" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.OffsetU`. - pub fn set_offset_u(&mut self, value: f32) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.OffsetU" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.OffsetV`. - pub fn offset_v(&self) -> f32 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.OffsetV" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.OffsetV`. - pub fn set_offset_v(&mut self, value: f32) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.OffsetV" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RGBA`. - pub fn rgba(&self) -> libremetaverse_types::Color4 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.TextureEntryFace.RGBA") - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RGBA`. - pub fn set_rgba(&mut self, value: libremetaverse_types::Color4) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Primitive.TextureEntryFace.RGBA") - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RenderMaterialID`. - pub fn render_material_id(&self) -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.RenderMaterialID" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RenderMaterialID`. - pub fn set_render_material_id(&mut self, value: libremetaverse_types::UUID) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.RenderMaterialID" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RepeatU`. - pub fn repeat_u(&self) -> f32 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.RepeatU" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RepeatU`. - pub fn set_repeat_u(&mut self, value: f32) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.RepeatU" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RepeatV`. - pub fn repeat_v(&self) -> f32 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.RepeatV" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RepeatV`. - pub fn set_repeat_v(&mut self, value: f32) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.RepeatV" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Rotation`. - pub fn rotation(&self) -> f32 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Rotation" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Rotation`. - pub fn set_rotation(&mut self, value: f32) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Rotation" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Shiny`. - pub fn shiny(&self) -> libremetaverse::Shininess { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Shiny" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Shiny`. - pub fn set_shiny(&mut self, value: libremetaverse::Shininess) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Shiny" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.TexMapType`. - pub fn tex_map_type(&self) -> libremetaverse::MappingType { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.TexMapType" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.TexMapType`. - pub fn set_tex_map_type(&mut self, value: libremetaverse::MappingType) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.TexMapType" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.TextureID`. - pub fn texture_id(&self) -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.TextureID" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.TextureID`. - pub fn set_texture_id(&mut self, value: libremetaverse_types::UUID) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.TextureID" - ) - } - /// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Valid`. - pub fn valid(&self) -> bool { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Primitive.TextureEntryFace.Valid" - ) - } -} +/// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.#ctor(LibreMetaverse.Primitive.TextureEntryFace)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.Clone`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.FromOSD(LibreMetaverse.StructuredData.OSD,LibreMetaverse.Primitive.TextureEntryFace,System.Int32@)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.GetHashCode`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.GetOSD(System.Int32)`. +/// C# member: `M:LibreMetaverse.Primitive.TextureEntryFace.ToString`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Bump`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Fullbright`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Glow`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.MaterialID`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.MediaFlags`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.OffsetU`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.OffsetV`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RGBA`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RenderMaterialID`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RepeatU`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.RepeatV`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Rotation`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Shiny`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.TexMapType`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.TextureID`. +/// C# member: `P:LibreMetaverse.Primitive.TextureEntryFace.Valid`. +pub use crate::object_model::PrimitiveTextureEntryFace; /// C# type: `T:LibreMetaverse.ProductInfoEventArgs`. /// C# member: `M:LibreMetaverse.ProductInfoEventArgs.#ctor(LibreMetaverse.Messages.Linden.ProductInfoRequestMessage)`. @@ -57608,236 +56705,27 @@ pub mod marketplace { pub mod materials { /// C# type: `T:LibreMetaverse.Materials.LegacyMaterial`. - pub struct LegacyMaterial; - impl LegacyMaterial { - /// C# member: `M:LibreMetaverse.Materials.LegacyMaterial.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.Materials.LegacyMaterial.#ctor") - } - /// C# member: `M:LibreMetaverse.Materials.LegacyMaterial.#ctor(LibreMetaverse.StructuredData.OSDMap)`. - pub fn new_with_osd_map( - map_orig: libremetaverse_structured_data::OSDMap, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.Materials.LegacyMaterial.#ctor(LibreMetaverse.StructuredData.OSDMap)", - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.AlphaMaskCutoff`. - pub fn alpha_mask_cutoff(&self) -> u8 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.AlphaMaskCutoff" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.AlphaMaskCutoff`. - pub fn set_alpha_mask_cutoff(&mut self, value: u8) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.AlphaMaskCutoff" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.DiffuseAlphaMode`. - pub fn diffuse_alpha_mode(&self) -> libremetaverse::materials::LegacyMaterialAlphaMode { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.DiffuseAlphaMode" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.DiffuseAlphaMode`. - pub fn set_diffuse_alpha_mode( - &mut self, - value: libremetaverse::materials::LegacyMaterialAlphaMode, - ) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.DiffuseAlphaMode" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.EnvironmentIntensity`. - pub fn environment_intensity(&self) -> u8 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.EnvironmentIntensity" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.EnvironmentIntensity`. - pub fn set_environment_intensity(&mut self, value: u8) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.EnvironmentIntensity" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.ID`. - pub fn id(&self) -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Materials.LegacyMaterial.ID") - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.ID`. - pub fn set_id(&mut self, value: libremetaverse_types::UUID) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Materials.LegacyMaterial.ID") - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMap`. - pub fn normal_map(&self) -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMap" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMap`. - pub fn set_normal_map(&mut self, value: libremetaverse_types::UUID) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMap" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetX`. - pub fn normal_map_offset_x(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetX" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetX`. - pub fn set_normal_map_offset_x(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetX" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetY`. - pub fn normal_map_offset_y(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetY" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetY`. - pub fn set_normal_map_offset_y(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetY" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatX`. - pub fn normal_map_repeat_x(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatX" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatX`. - pub fn set_normal_map_repeat_x(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatX" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatY`. - pub fn normal_map_repeat_y(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatY" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatY`. - pub fn set_normal_map_repeat_y(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatY" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRotation`. - pub fn normal_map_rotation(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRotation" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRotation`. - pub fn set_normal_map_rotation(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRotation" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularColor`. - pub fn specular_color(&self) -> libremetaverse_types::Color4 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularColor" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularColor`. - pub fn set_specular_color(&mut self, value: libremetaverse_types::Color4) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularColor" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularExponent`. - pub fn specular_exponent(&self) -> u8 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularExponent" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularExponent`. - pub fn set_specular_exponent(&mut self, value: u8) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularExponent" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMap`. - pub fn specular_map(&self) -> libremetaverse_types::UUID { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMap" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMap`. - pub fn set_specular_map(&mut self, value: libremetaverse_types::UUID) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMap" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetX`. - pub fn specular_map_offset_x(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetX" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetX`. - pub fn set_specular_map_offset_x(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetX" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetY`. - pub fn specular_map_offset_y(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetY" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetY`. - pub fn set_specular_map_offset_y(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetY" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatX`. - pub fn specular_map_repeat_x(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatX" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatX`. - pub fn set_specular_map_repeat_x(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatX" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatY`. - pub fn specular_map_repeat_y(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatY" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatY`. - pub fn set_specular_map_repeat_y(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatY" - ) - } - /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRotation`. - pub fn specular_map_rotation(&self) -> f64 { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRotation" - ) - } - /// Setter for C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRotation`. - pub fn set_specular_map_rotation(&mut self, value: f64) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRotation" - ) - } - } + /// C# member: `M:LibreMetaverse.Materials.LegacyMaterial.#ctor`. + /// C# member: `M:LibreMetaverse.Materials.LegacyMaterial.#ctor(LibreMetaverse.StructuredData.OSDMap)`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.AlphaMaskCutoff`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.DiffuseAlphaMode`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.EnvironmentIntensity`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.ID`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMap`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetX`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapOffsetY`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatX`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRepeatY`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.NormalMapRotation`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularColor`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularExponent`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMap`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetX`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapOffsetY`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatX`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRepeatY`. + /// C# member: `P:LibreMetaverse.Materials.LegacyMaterial.SpecularMapRotation`. + pub use crate::object_model::LegacyMaterial; /// C# type: `T:LibreMetaverse.Materials.LegacyMaterialAlphaMode`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] diff --git a/crates/libremetaverse/src/lib.rs b/crates/libremetaverse/src/lib.rs index 7ed5508..28494fc 100644 --- a/crates/libremetaverse/src/lib.rs +++ b/crates/libremetaverse/src/lib.rs @@ -43,6 +43,7 @@ mod message_codec; mod message_decoder; mod network_manager; mod object_material; +mod object_model; #[rustfmt::skip] pub mod packet_catalog; mod packet_wire; diff --git a/crates/libremetaverse/src/object_model.rs b/crates/libremetaverse/src/object_model.rs new file mode 100644 index 0000000..af77998 --- /dev/null +++ b/crates/libremetaverse/src/object_model.rs @@ -0,0 +1,3408 @@ +//! Native primitive and object appearance model. +//! +//! The wire decoders in this module accept untrusted simulator blobs. Every +//! cursor advance is checked and every variable-size section is bounded by the +//! caller-provided slice before data is committed to the model. + +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] +#![allow(clippy::cast_precision_loss)] +#![allow(clippy::cast_sign_loss)] +#![allow(clippy::field_reassign_with_default)] +#![allow(clippy::inherent_to_string)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::missing_panics_doc)] +#![allow(clippy::must_use_candidate)] +#![allow(clippy::needless_pass_by_value)] +#![allow(clippy::should_implement_trait)] +#![allow(clippy::too_many_lines)] + +use crate::{ + Animation, BitPack, Bumpiness, Grass, MappingType, MediaEntry, NameValue, Permissions, + PrimitiveParticleSystemBlendFunc, PrimitiveParticleSystemParticleDataFlags, + PrimitiveParticleSystemSourcePattern, PrimitivePhysicsProperties, PrimitiveTextureAnimMode, + Shininess, Tree, +}; +use libremetaverse_structured_data::{OSD, OSDMap}; +use libremetaverse_types::compat::Object; +use libremetaverse_types::{ + AttachmentPoint, ClickAction, Color4, Error, HoleType, JointType, Material, ObjectCategory, + PCode, PathCurve, PrimFlags, PrimType, ProfileCurve, Quaternion, SaleType, SculptType, + SoundFlags, UUID, Vector2, Vector3, Vector4, +}; +use std::collections::HashMap; +use std::fmt::Write as _; +use std::hash::{Hash, Hasher}; +use std::time::{SystemTime, UNIX_EPOCH}; + +const MAX_OSD_FACE_ENTRIES: usize = 46; +const MAX_TEXTURE_ENTRY_BYTES: usize = 64 * 1024; +const MAX_EXTRA_PARAMS: usize = 64; +const MAX_EXTRA_PARAM_BYTES: usize = 64 * 1024; + +fn checked_window(data: &[u8], pos: i32, length: usize) -> Result<&[u8], Error> { + let start = usize::try_from(pos).map_err(|_| Error::IndexOutOfRange)?; + let end = start.checked_add(length).ok_or(Error::IndexOutOfRange)?; + data.get(start..end).ok_or(Error::IndexOutOfRange) +} + +fn read_f32(data: &[u8], offset: usize) -> Result { + let bytes: [u8; 4] = data + .get(offset..offset + 4) + .ok_or(Error::IndexOutOfRange)? + .try_into() + .map_err(|_| Error::IndexOutOfRange)?; + Ok(f32::from_le_bytes(bytes)) +} + +fn map(osd: OSD) -> Option> { + match osd { + OSD::Map(value) => Some(value), + _ => None, + } +} + +fn map_real(values: Option<&HashMap>, key: &str, default: f32) -> f32 { + values + .and_then(|map| map.get(key)) + .and_then(|value| value.as_real().ok()) + .map_or(default, |value| value as f32) +} + +fn map_i32(values: Option<&HashMap>, key: &str, default: i32) -> i32 { + values + .and_then(|map| map.get(key)) + .and_then(|value| value.as_integer().ok()) + .unwrap_or(default) +} + +fn map_u32(values: Option<&HashMap>, key: &str, default: u32) -> u32 { + values + .and_then(|map| map.get(key)) + .and_then(|value| value.as_u_integer().ok()) + .unwrap_or(default) +} + +fn map_bool(values: Option<&HashMap>, key: &str, default: bool) -> bool { + values + .and_then(|map| map.get(key)) + .and_then(|value| value.as_boolean().ok()) + .unwrap_or(default) +} + +fn map_uuid(values: Option<&HashMap>, key: &str, default: UUID) -> UUID { + values + .and_then(|map| map.get(key)) + .and_then(|value| value.as_uuid().ok()) + .unwrap_or(default) +} + +fn map_vector3(values: Option<&HashMap>, key: &str, default: Vector3) -> Vector3 { + values + .and_then(|map| map.get(key)) + .filter(|value| matches!(value, OSD::Array(items) if items.len() == 3)) + .and_then(|value| value.as_vector3().ok()) + .unwrap_or(default) +} + +fn hash_i32(value: &T) -> i32 { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + value.hash(&mut hasher); + hasher.finish() as i32 +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimitiveConstructionData { + pub material: Material, + pub p_code: PCode, + pub path_begin: f32, + pub path_curve: PathCurve, + pub path_end: f32, + pub path_radius_offset: f32, + pub path_revolutions: f32, + pub path_scale_x: f32, + pub path_scale_y: f32, + pub path_shear_x: f32, + pub path_shear_y: f32, + pub path_skew: f32, + pub path_taper_x: f32, + pub path_taper_y: f32, + pub path_twist: f32, + pub path_twist_begin: f32, + pub profile_begin: f32, + pub profile_end: f32, + pub profile_hollow: f32, + pub state: u8, + pub profile_curve_with_field: u8, +} + +impl Default for PrimitiveConstructionData { + fn default() -> Self { + Self { + material: Material::Stone, + p_code: PCode::Prim, + path_begin: 0.0, + path_curve: PathCurve::Line, + path_end: 1.0, + path_radius_offset: 0.0, + path_revolutions: 1.0, + path_scale_x: 1.0, + path_scale_y: 1.0, + path_shear_x: 0.0, + path_shear_y: 0.0, + path_skew: 0.0, + path_taper_x: 0.0, + path_taper_y: 0.0, + path_twist: 0.0, + path_twist_begin: 0.0, + profile_begin: 0.0, + profile_end: 1.0, + profile_hollow: 0.0, + state: 0, + profile_curve_with_field: ProfileCurve::Circle as u8, + } + } +} + +impl PrimitiveConstructionData { + pub fn new_with_constructor() -> Result { + Ok(Self::default()) + } + + pub fn new_with_construction_data(other: Self) -> Result { + Ok(other) + } + + pub fn get_hash_code(&self) -> i32 { + let floats = [ + self.path_begin, + self.path_end, + self.path_radius_offset, + self.path_revolutions, + self.path_scale_x, + self.path_scale_y, + self.path_shear_x, + self.path_shear_y, + self.path_skew, + self.path_taper_x, + self.path_taper_y, + self.path_twist, + self.path_twist_begin, + self.profile_begin, + self.profile_end, + self.profile_hollow, + ]; + floats.iter().fold( + i32::from(self.profile_curve_with_field) + ^ i32::from(self.path_curve as u8) + ^ i32::from(self.material as u8) + ^ i32::from(self.p_code as u8) + ^ i32::from(self.state), + |hash, value| hash ^ i32::from_ne_bytes(value.to_bits().to_ne_bytes()), + ) + } + + pub fn attachment_point(&self) -> AttachmentPoint { + attachment_point_from_u8(self.state.rotate_left(4)) + } + + pub fn set_attachment_point(&mut self, value: AttachmentPoint) { + self.state = (value as u8).rotate_left(4); + } + + pub fn path_begin_scale(&self) -> Vector2 { + Vector2 { + x: if self.path_scale_x > 1.0 { + 2.0 - self.path_scale_x + } else { + 1.0 + }, + y: if self.path_scale_y > 1.0 { + 2.0 - self.path_scale_y + } else { + 1.0 + }, + } + } + + pub fn path_end_scale(&self) -> Vector2 { + Vector2 { + x: if self.path_scale_x < 1.0 { + self.path_scale_x + } else { + 1.0 + }, + y: if self.path_scale_y < 1.0 { + self.path_scale_y + } else { + 1.0 + }, + } + } + + pub fn profile_curve_with_property(&self) -> ProfileCurve { + profile_curve_from_u8(self.profile_curve_with_field & 0x0f) + } + + pub fn set_profile_curve_with_property(&mut self, value: ProfileCurve) { + self.profile_curve_with_field = (self.profile_curve_with_field & 0xf0) | value as u8; + } + + pub fn profile_hole(&self) -> HoleType { + HoleType(self.profile_curve_with_field & 0xf0) + } + + pub fn set_profile_hole(&mut self, value: HoleType) { + self.profile_curve_with_field = (self.profile_curve_with_field & 0x0f) | (value.0 & 0xf0); + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimitiveFlexibleData { + pub drag: f32, + pub force: Vector3, + pub gravity: f32, + pub softness: i32, + pub tension: f32, + pub wind: f32, +} + +impl Default for PrimitiveFlexibleData { + fn default() -> Self { + Self { + drag: 0.0, + force: Vector3::zero(), + gravity: 0.0, + softness: 0, + tension: 0.0, + wind: 0.0, + } + } +} + +impl PrimitiveFlexibleData { + pub fn new_with_constructor() -> Result { + Ok(Self::default()) + } + + pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { + let bytes = checked_window(&data, pos, 16)?; + Ok(Self { + softness: i32::from(((bytes[0] & 0x80) >> 6) | ((bytes[1] & 0x80) >> 7)), + tension: f32::from(bytes[0] & 0x7f) / 10.0, + drag: f32::from(bytes[1] & 0x7f) / 10.0, + gravity: f32::from(bytes[2]) / 10.0 - 10.0, + wind: f32::from(bytes[3]) / 10.0, + force: Vector3::new_with_bytes_int32(bytes[4..].to_vec(), 0)?, + }) + } + + pub fn get_bytes(&self) -> Result, Error> { + let mut data = vec![0_u8; 16]; + data[0] = ((self.softness & 2) << 6) as u8 | ((self.tension * 10.01) as u8 & 0x7f); + data[1] = ((self.softness & 1) << 7) as u8 | ((self.drag * 10.01) as u8 & 0x7f); + data[2] = ((self.gravity + 10.0) * 10.01) as u8; + data[3] = (self.wind * 10.01) as u8; + self.force.to_bytes(&mut data, 4)?; + Ok(data) + } + + pub fn get_osd(&self) -> Result { + Ok(OSD::Map(HashMap::from([ + ("simulate_lod".into(), OSD::Integer(self.softness)), + ("gravity".into(), OSD::Real(f64::from(self.gravity))), + ("air_friction".into(), OSD::Real(f64::from(self.drag))), + ("wind_sensitivity".into(), OSD::Real(f64::from(self.wind))), + ("tension".into(), OSD::Real(f64::from(self.tension))), + ("user_force".into(), OSD::from_vector3(self.force)?), + ]))) + } + + pub fn from_osd(osd: OSD) -> Result { + let Some(values) = map(osd) else { + return Ok(Self::default()); + }; + Ok(Self { + softness: map_i32(Some(&values), "simulate_lod", 0), + gravity: map_real(Some(&values), "gravity", 0.0), + drag: map_real(Some(&values), "air_friction", 0.0), + wind: map_real(Some(&values), "wind_sensitivity", 0.0), + tension: map_real(Some(&values), "tension", 0.0), + force: map_vector3(Some(&values), "user_force", Vector3::zero()), + }) + } + + pub fn get_hash_code(&self) -> i32 { + hash_i32(&self.get_bytes().unwrap_or_default()) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimitiveLightData { + pub color: Color4, + pub cutoff: f32, + pub falloff: f32, + pub intensity: f32, + pub radius: f32, +} + +impl Default for PrimitiveLightData { + fn default() -> Self { + Self { + color: Color4::black(), + cutoff: 0.0, + falloff: 0.0, + intensity: 0.0, + radius: 0.0, + } + } +} + +impl PrimitiveLightData { + pub fn new_with_constructor() -> Result { + Ok(Self::default()) + } + + pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { + let bytes = checked_window(&data, pos, 16)?; + let encoded = Color4::new_with_bytes_int32_boolean(bytes[..4].to_vec(), 0, false)?; + Ok(Self { + color: Color4 { + r: encoded.r, + g: encoded.g, + b: encoded.b, + a: 1.0, + }, + intensity: encoded.a, + radius: read_f32(bytes, 4)?, + cutoff: read_f32(bytes, 8)?, + falloff: read_f32(bytes, 12)?, + }) + } + + pub fn get_bytes(&self) -> Result, Error> { + let mut data = vec![0_u8; 16]; + Color4 { + r: self.color.r, + g: self.color.g, + b: self.color.b, + a: self.intensity.clamp(0.0, 1.0), + } + .to_bytes_with_bytes_int32(&mut data, 0)?; + data[4..8].copy_from_slice(&self.radius.to_le_bytes()); + data[8..12].copy_from_slice(&self.cutoff.to_le_bytes()); + data[12..16].copy_from_slice(&self.falloff.to_le_bytes()); + Ok(data) + } + + pub fn get_osd(&self) -> Result { + Ok(OSD::Map(HashMap::from([ + ("color".into(), OSD::from_color4(self.color)?), + ("intensity".into(), OSD::Real(f64::from(self.intensity))), + ("radius".into(), OSD::Real(f64::from(self.radius))), + ("cutoff".into(), OSD::Real(f64::from(self.cutoff))), + ("falloff".into(), OSD::Real(f64::from(self.falloff))), + ]))) + } + + pub fn from_osd(osd: OSD) -> Result { + let Some(values) = map(osd) else { + return Ok(Self::default()); + }; + Ok(Self { + color: values + .get("color") + .and_then(|v| v.as_color4().ok()) + .unwrap_or_else(Color4::black), + intensity: map_real(Some(&values), "intensity", 0.0), + radius: map_real(Some(&values), "radius", 0.0), + cutoff: map_real(Some(&values), "cutoff", 0.0), + falloff: map_real(Some(&values), "falloff", 0.0), + }) + } + + pub fn get_hash_code(&self) -> i32 { + hash_i32(&self.get_bytes().unwrap_or_default()) + } + pub fn to_string(&self) -> String { + format!( + "Color: {:?} Intensity: {} Radius: {} Cutoff: {} Falloff: {}", + self.color, self.intensity, self.radius, self.cutoff, self.falloff + ) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimitiveLightImage { + pub light_texture: UUID, + pub params: Vector3, +} + +impl Default for PrimitiveLightImage { + fn default() -> Self { + Self { + light_texture: UUID::zero(), + params: Vector3::zero(), + } + } +} + +impl PrimitiveLightImage { + pub fn new_with_constructor() -> Result { + Ok(Self::default()) + } + pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { + let bytes = checked_window(&data, pos, 28)?; + Ok(Self { + light_texture: UUID::new_with_bytes_int32(bytes[..16].to_vec(), 0)?, + params: Vector3::new_with_bytes_int32(bytes[16..].to_vec(), 0)?, + }) + } + pub fn get_bytes(&self) -> Result, Error> { + let mut data = vec![0_u8; 28]; + self.light_texture.to_bytes(&mut data, 0)?; + self.params.to_bytes(&mut data, 16)?; + Ok(data) + } + pub fn get_osd(&self) -> Result { + Ok(OSD::Map(HashMap::from([ + ("texture".into(), OSD::UUID(self.light_texture)), + ("params".into(), OSD::from_vector3(self.params)?), + ]))) + } + pub fn from_osd(osd: OSD) -> Result { + let Some(values) = map(osd) else { + return Ok(Self::default()); + }; + Ok(Self { + light_texture: map_uuid(Some(&values), "texture", UUID::zero()), + params: map_vector3(Some(&values), "params", Vector3::zero()), + }) + } + pub fn get_hash_code(&self) -> i32 { + hash_i32(&self.get_bytes().unwrap_or_default()) + } + pub fn to_string(&self) -> String { + format!( + "LightTexture: {} Params: {:?}", + self.light_texture, self.params + ) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimitiveSculptData { + pub sculpt_texture: UUID, + type_bits: u8, +} + +impl Default for PrimitiveSculptData { + fn default() -> Self { + Self { + sculpt_texture: UUID::zero(), + type_bits: SculptType::None as u8, + } + } +} + +impl PrimitiveSculptData { + pub fn new_with_constructor() -> Result { + Ok(Self::default()) + } + pub fn new_with_bytes_int32(data: Vec, pos: i32) -> Result { + let bytes = checked_window(&data, pos, 17)?; + Ok(Self { + sculpt_texture: UUID::new_with_bytes_int32(bytes[..16].to_vec(), 0)?, + type_bits: bytes[16], + }) + } + pub fn get_bytes(&self) -> Result, Error> { + let mut out = self.sculpt_texture.get_bytes()?; + out.push(self.type_bits); + Ok(out) + } + pub fn get_osd(&self) -> Result { + Ok(OSD::Map(HashMap::from([ + ("texture".into(), OSD::UUID(self.sculpt_texture)), + ("type".into(), OSD::Integer(i32::from(self.type_bits))), + ]))) + } + pub fn from_osd(osd: OSD) -> Result { + let Some(values) = map(osd) else { + return Ok(Self::default()); + }; + Ok(Self { + sculpt_texture: map_uuid(Some(&values), "texture", UUID::zero()), + type_bits: map_i32(Some(&values), "type", 0) as u8, + }) + } + pub fn get_hash_code(&self) -> i32 { + self.sculpt_texture.get_hash_code() ^ i32::from(self.type_bits) + } + pub fn invert(&self) -> bool { + self.type_bits & SculptType::Invert as u8 != 0 + } + pub fn mirror(&self) -> bool { + self.type_bits & SculptType::Mirror as u8 != 0 + } + pub fn type_(&self) -> SculptType { + sculpt_type_from_u8(self.type_bits & 7) + } + pub fn set_type_(&mut self, value: SculptType) { + self.type_bits = value as u8; + } +} + +#[derive(Clone, Debug)] +pub struct PrimitiveObjectProperties { + pub aggregate_perm_textures: u8, + pub aggregate_perm_textures_owner: u8, + pub aggregate_perms: u8, + pub category: ObjectCategory, + pub creation_date: SystemTime, + pub creator_id: UUID, + pub description: String, + pub folder_id: UUID, + pub from_task_id: UUID, + pub group_id: UUID, + pub inventory_serial: i16, + pub item_id: UUID, + pub last_owner_id: UUID, + pub name: String, + pub object_id: UUID, + pub owner_id: UUID, + pub ownership_cost: i32, + pub permissions: Permissions, + pub sale_price: i32, + pub sale_type: SaleType, + pub sit_name: String, + pub texture_i_ds: Vec, + pub touch_name: String, +} + +impl Default for PrimitiveObjectProperties { + fn default() -> Self { + Self { + aggregate_perm_textures: 0, + aggregate_perm_textures_owner: 0, + aggregate_perms: 0, + category: ObjectCategory::None, + creation_date: UNIX_EPOCH, + creator_id: UUID::zero(), + description: String::new(), + folder_id: UUID::zero(), + from_task_id: UUID::zero(), + group_id: UUID::zero(), + inventory_serial: 0, + item_id: UUID::zero(), + last_owner_id: UUID::zero(), + name: String::new(), + object_id: UUID::zero(), + owner_id: UUID::zero(), + ownership_cost: 0, + permissions: Permissions::no_permissions(), + sale_price: 0, + sale_type: SaleType::Not, + sit_name: String::new(), + texture_i_ds: Vec::new(), + touch_name: String::new(), + } + } +} + +impl PrimitiveObjectProperties { + pub fn new() -> Result { + Ok(Self::default()) + } + pub fn get_texture_id_bytes(&self) -> Result, Error> { + let capacity = self + .texture_i_ds + .len() + .checked_mul(16) + .ok_or(Error::Argument)?; + let mut bytes = Vec::with_capacity(capacity); + for id in &self.texture_i_ds { + bytes.extend_from_slice(&id.get_bytes()?); + } + Ok(bytes) + } + pub fn set_family_properties(&mut self, props: Self) -> Result<(), Error> { + self.object_id = props.object_id; + self.owner_id = props.owner_id; + self.group_id = props.group_id; + self.permissions = props.permissions; + self.ownership_cost = props.ownership_cost; + self.sale_type = props.sale_type; + self.sale_price = props.sale_price; + self.category = props.category; + self.last_owner_id = props.last_owner_id; + self.name = props.name; + self.description = props.description; + Ok(()) + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct PrimitiveTextureAnimation { + pub face: u32, + pub flags: PrimitiveTextureAnimMode, + pub length: f32, + pub rate: f32, + pub size_x: u32, + pub size_y: u32, + pub start: f32, +} + +impl Default for PrimitiveTextureAnimation { + fn default() -> Self { + Self { + face: 0, + flags: PrimitiveTextureAnimMode::ANIM_OFF, + length: 0.0, + rate: 0.0, + size_x: 0, + size_y: 0, + start: 0.0, + } + } +} + +impl PrimitiveTextureAnimation { + pub fn new(data: Vec, pos: i32) -> Result { + let Ok(bytes) = checked_window(&data, pos, 16) else { + return Ok(Self::default()); + }; + Ok(Self { + flags: PrimitiveTextureAnimMode(u32::from(bytes[0])), + face: u32::from(bytes[1]), + size_x: u32::from(bytes[2]), + size_y: u32::from(bytes[3]), + start: read_f32(bytes, 4)?, + length: read_f32(bytes, 8)?, + rate: read_f32(bytes, 12)?, + }) + } + pub fn get_bytes(&self) -> Result, Error> { + let mut data = vec![ + self.flags.0 as u8, + self.face as u8, + self.size_x as u8, + self.size_y as u8, + ]; + data.extend_from_slice(&self.start.to_le_bytes()); + data.extend_from_slice(&self.length.to_le_bytes()); + data.extend_from_slice(&self.rate.to_le_bytes()); + Ok(data) + } + pub fn get_osd(&self) -> Result { + Ok(OSD::Map(HashMap::from([ + ("face".into(), OSD::from_u_integer(self.face)?), + ("flags".into(), OSD::from_u_integer(self.flags.0)?), + ("length".into(), OSD::Real(f64::from(self.length))), + ("rate".into(), OSD::Real(f64::from(self.rate))), + ("size_x".into(), OSD::from_u_integer(self.size_x)?), + ("size_y".into(), OSD::from_u_integer(self.size_y)?), + ("start".into(), OSD::Real(f64::from(self.start))), + ]))) + } + pub fn from_osd(osd: OSD) -> Result { + let Some(values) = map(osd) else { + return Ok(Self::default()); + }; + Ok(Self { + face: map_u32(Some(&values), "face", 0), + flags: PrimitiveTextureAnimMode(map_u32(Some(&values), "flags", 0)), + length: map_real(Some(&values), "length", 0.0), + rate: map_real(Some(&values), "rate", 0.0), + size_x: map_u32(Some(&values), "size_x", 0), + size_y: map_u32(Some(&values), "size_y", 0), + start: map_real(Some(&values), "start", 0.0), + }) + } + pub fn equals_with_texture_animation(&self, other: Self) -> bool { + *self == other + } + pub fn equals_with_object(&self, obj: Option) -> bool { + obj.as_ref() + .and_then(Object::downcast_ref::) + .is_some_and(|other| self == other) + } + pub fn get_hash_code(&self) -> i32 { + hash_i32(&self.get_bytes().unwrap_or_default()) + } +} + +const ATTR_TEXTURE_ID: u32 = 1 << 0; +const ATTR_RGBA: u32 = 1 << 1; +const ATTR_REPEAT_U: u32 = 1 << 2; +const ATTR_REPEAT_V: u32 = 1 << 3; +const ATTR_OFFSET_U: u32 = 1 << 4; +const ATTR_OFFSET_V: u32 = 1 << 5; +const ATTR_ROTATION: u32 = 1 << 6; +const ATTR_MATERIAL: u32 = 1 << 7; +const ATTR_MEDIA: u32 = 1 << 8; +const ATTR_GLOW: u32 = 1 << 9; +const ATTR_MATERIAL_ID: u32 = 1 << 10; +const ATTR_RENDER_MATERIAL_ID: u32 = 1 << 11; +const ATTR_ALL: u32 = u32::MAX; + +#[derive(Clone, Debug, PartialEq)] +struct TextureFaceData { + rgba: Color4, + repeat_u: f32, + repeat_v: f32, + offset_u: f32, + offset_v: f32, + rotation: f32, + glow: f32, + material: u8, + media: u8, + attributes: u32, + texture_id: UUID, + material_id: UUID, + render_material_id: UUID, +} + +impl Default for TextureFaceData { + fn default() -> Self { + Self { + rgba: Color4::white(), + repeat_u: 1.0, + repeat_v: 1.0, + offset_u: 0.0, + offset_v: 0.0, + rotation: 0.0, + glow: 0.0, + material: 0, + media: 0, + attributes: ATTR_ALL, + texture_id: UUID::zero(), + material_id: UUID::zero(), + render_material_id: UUID::zero(), + } + } +} + +#[derive(Debug)] +pub struct PrimitiveTextureEntryFace { + data: std::sync::Arc>, + default: Option>>, +} + +impl Default for PrimitiveTextureEntryFace { + fn default() -> Self { + Self::default_face() + } +} + +impl Clone for PrimitiveTextureEntryFace { + fn clone(&self) -> Self { + self.deep_clone() + } +} + +impl PartialEq for PrimitiveTextureEntryFace { + fn eq(&self, other: &Self) -> bool { + self.rgba() == other.rgba() + && self.repeat_u() == other.repeat_u() + && self.repeat_v() == other.repeat_v() + && self.offset_u() == other.offset_u() + && self.offset_v() == other.offset_v() + && self.rotation() == other.rotation() + && self.glow() == other.glow() + && self.material() == other.material() + && self.media() == other.media() + && self.texture_id() == other.texture_id() + && self.material_id() == other.material_id() + && self.render_material_id() == other.render_material_id() + } +} + +impl PrimitiveTextureEntryFace { + fn default_face() -> Self { + Self { + data: std::sync::Arc::new(std::sync::RwLock::new(TextureFaceData::default())), + default: None, + } + } + + fn inheriting(default: std::sync::Arc>) -> Self { + let data = TextureFaceData { + attributes: 0, + ..TextureFaceData::default() + }; + Self { + data: std::sync::Arc::new(std::sync::RwLock::new(data)), + default: Some(default), + } + } + + fn read_data(&self) -> std::sync::RwLockReadGuard<'_, TextureFaceData> { + self.data + .read() + .unwrap_or_else(std::sync::PoisonError::into_inner) + } + + fn write_data(&self) -> std::sync::RwLockWriteGuard<'_, TextureFaceData> { + self.data + .write() + .unwrap_or_else(std::sync::PoisonError::into_inner) + } + + fn inherited(&self) -> Option> { + self.default.as_ref().map(|value| { + value + .read() + .unwrap_or_else(std::sync::PoisonError::into_inner) + }) + } + + fn deep_clone(&self) -> Self { + let default = self.default.as_ref().map(|value| { + std::sync::Arc::new(std::sync::RwLock::new( + value + .read() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .clone(), + )) + }); + Self { + data: std::sync::Arc::new(std::sync::RwLock::new(self.read_data().clone())), + default, + } + } + + fn clone_with_default( + &self, + default: Option>>, + ) -> Self { + Self { + data: std::sync::Arc::new(std::sync::RwLock::new(self.read_data().clone())), + default, + } + } + + pub fn new(default_texture: Option) -> Result { + Ok(default_texture.map_or_else(Self::default_face, |face| Self::inheriting(face.data))) + } + + pub fn clone(&self) -> Result { + Ok(Object::opaque(self.deep_clone())) + } + + pub fn valid(&self) -> bool { + self.default.is_some() + } + + fn effective(&self, attribute: u32, own: impl Fn(&TextureFaceData) -> T) -> T { + let data = self.read_data(); + if data.attributes & attribute != 0 { + return own(&data); + } + self.inherited() + .map_or_else(|| own(&data), |default| own(&default)) + } + + fn material(&self) -> u8 { + self.effective(ATTR_MATERIAL, |value| value.material) + } + fn media(&self) -> u8 { + self.effective(ATTR_MEDIA, |value| value.media) + } + fn set_material(&mut self, value: u8) { + let mut data = self.write_data(); + data.material = value; + data.attributes |= ATTR_MATERIAL; + } + fn set_media(&mut self, value: u8) { + let mut data = self.write_data(); + data.media = value; + data.attributes |= ATTR_MEDIA; + } + + pub fn rgba(&self) -> Color4 { + self.effective(ATTR_RGBA, |value| value.rgba) + } + pub fn set_rgba(&mut self, value: Color4) { + let mut data = self.write_data(); + data.rgba = value; + data.attributes |= ATTR_RGBA; + } + pub fn repeat_u(&self) -> f32 { + self.effective(ATTR_REPEAT_U, |value| value.repeat_u) + } + pub fn set_repeat_u(&mut self, value: f32) { + let mut data = self.write_data(); + data.repeat_u = value; + data.attributes |= ATTR_REPEAT_U; + } + pub fn repeat_v(&self) -> f32 { + self.effective(ATTR_REPEAT_V, |value| value.repeat_v) + } + pub fn set_repeat_v(&mut self, value: f32) { + let mut data = self.write_data(); + data.repeat_v = value; + data.attributes |= ATTR_REPEAT_V; + } + pub fn offset_u(&self) -> f32 { + self.effective(ATTR_OFFSET_U, |value| value.offset_u) + } + pub fn set_offset_u(&mut self, value: f32) { + let mut data = self.write_data(); + data.offset_u = value; + data.attributes |= ATTR_OFFSET_U; + } + pub fn offset_v(&self) -> f32 { + self.effective(ATTR_OFFSET_V, |value| value.offset_v) + } + pub fn set_offset_v(&mut self, value: f32) { + let mut data = self.write_data(); + data.offset_v = value; + data.attributes |= ATTR_OFFSET_V; + } + pub fn rotation(&self) -> f32 { + self.effective(ATTR_ROTATION, |value| value.rotation) + } + pub fn set_rotation(&mut self, value: f32) { + let mut data = self.write_data(); + data.rotation = value; + data.attributes |= ATTR_ROTATION; + } + pub fn glow(&self) -> f32 { + self.effective(ATTR_GLOW, |value| value.glow) + } + pub fn set_glow(&mut self, value: f32) { + let mut data = self.write_data(); + data.glow = value; + data.attributes |= ATTR_GLOW; + } + pub fn texture_id(&self) -> UUID { + self.effective(ATTR_TEXTURE_ID, |value| value.texture_id) + } + pub fn set_texture_id(&mut self, value: UUID) { + let mut data = self.write_data(); + data.texture_id = value; + data.attributes |= ATTR_TEXTURE_ID; + } + pub fn material_id(&self) -> UUID { + self.effective(ATTR_MATERIAL_ID, |value| value.material_id) + } + pub fn set_material_id(&mut self, value: UUID) { + let mut data = self.write_data(); + data.material_id = value; + data.attributes |= ATTR_MATERIAL_ID; + } + pub fn render_material_id(&self) -> UUID { + self.effective(ATTR_RENDER_MATERIAL_ID, |value| value.render_material_id) + } + pub fn set_render_material_id(&mut self, value: UUID) { + let mut data = self.write_data(); + data.render_material_id = value; + data.attributes |= ATTR_RENDER_MATERIAL_ID; + } + pub fn bump(&self) -> Bumpiness { + bumpiness_from_u8(self.material() & 0x1f) + } + pub fn set_bump(&mut self, value: Bumpiness) { + self.set_material((self.material() & 0xe0) | value as u8); + } + pub fn shiny(&self) -> Shininess { + shininess_from_u8(self.material() & 0xc0) + } + pub fn set_shiny(&mut self, value: Shininess) { + self.set_material((self.material() & 0x3f) | value as u8); + } + pub fn fullbright(&self) -> bool { + self.material() & 0x20 != 0 + } + pub fn set_fullbright(&mut self, value: bool) { + self.set_material((self.material() & !0x20) | if value { 0x20 } else { 0 }); + } + pub fn media_flags(&self) -> bool { + self.media() & 1 != 0 + } + pub fn set_media_flags(&mut self, value: bool) { + self.set_media((self.media() & !1) | u8::from(value)); + } + pub fn tex_map_type(&self) -> MappingType { + mapping_type_from_u8(self.media() & 0x06) + } + pub fn set_tex_map_type(&mut self, value: MappingType) { + self.set_media((self.media() & !0x06) | value as u8); + } + + pub fn get_osd(&self, face_number: i32) -> Result { + let mut values = HashMap::from([ + ("colors".into(), OSD::from_color4(self.rgba())?), + ("scales".into(), OSD::Real(f64::from(self.repeat_u()))), + ("scalet".into(), OSD::Real(f64::from(self.repeat_v()))), + ("offsets".into(), OSD::Real(f64::from(self.offset_u()))), + ("offsett".into(), OSD::Real(f64::from(self.offset_v()))), + ("imagerot".into(), OSD::Real(f64::from(self.rotation()))), + ("bump".into(), OSD::Integer(self.bump() as i32)), + ("shiny".into(), OSD::Integer(self.shiny() as i32)), + ("fullbright".into(), OSD::Boolean(self.fullbright())), + ("media_flags".into(), OSD::Boolean(self.media_flags())), + ("mapping".into(), OSD::Integer(self.tex_map_type() as i32)), + ("glow".into(), OSD::Real(f64::from(self.glow()))), + ( + "imageid".into(), + OSD::UUID( + if self.texture_id() == PrimitiveTextureEntry::white_texture() { + UUID::zero() + } else { + self.texture_id() + }, + ), + ), + ("materialid".into(), OSD::UUID(self.material_id())), + ( + "rendermaterialid".into(), + OSD::UUID(self.render_material_id()), + ), + ]); + if face_number >= 0 { + values.insert("face_number".into(), OSD::Integer(face_number)); + } + Ok(OSD::Map(values)) + } + + pub fn from_osd( + osd: OSD, + default_face: Option, + face_number: &mut i32, + ) -> Result { + let values = map(osd).ok_or(Error::Argument)?; + *face_number = map_i32(Some(&values), "face_number", -1); + let mut face = + default_face.map_or_else(Self::default_face, |value| Self::inheriting(value.data)); + face.set_rgba( + values + .get("colors") + .and_then(|v| v.as_color4().ok()) + .unwrap_or_else(Color4::white), + ); + face.set_repeat_u(map_real(Some(&values), "scales", 1.0)); + face.set_repeat_v(map_real(Some(&values), "scalet", 1.0)); + face.set_offset_u(map_real(Some(&values), "offsets", 0.0)); + face.set_offset_v(map_real(Some(&values), "offsett", 0.0)); + face.set_rotation(map_real(Some(&values), "imagerot", 0.0)); + face.set_bump(bumpiness_from_u8(map_i32(Some(&values), "bump", 0) as u8)); + face.set_shiny(shininess_from_u8(map_i32(Some(&values), "shiny", 0) as u8)); + face.set_fullbright(map_bool(Some(&values), "fullbright", false)); + face.set_media_flags(map_bool(Some(&values), "media_flags", false)); + face.set_tex_map_type(mapping_type_from_u8( + map_i32(Some(&values), "mapping", 0) as u8 + )); + face.set_glow(map_real(Some(&values), "glow", 0.0)); + face.set_texture_id(map_uuid(Some(&values), "imageid", UUID::zero())); + face.set_material_id(map_uuid(Some(&values), "materialid", UUID::zero())); + face.set_render_material_id(map_uuid(Some(&values), "rendermaterialid", UUID::zero())); + Ok(face) + } + + pub fn get_hash_code(&self) -> i32 { + hash_i32(&( + self.rgba().get_hash_code(), + self.repeat_u().to_bits(), + self.repeat_v().to_bits(), + self.offset_u().to_bits(), + self.offset_v().to_bits(), + self.rotation().to_bits(), + self.glow().to_bits(), + self.material(), + self.media(), + self.texture_id(), + self.material_id(), + self.render_material_id(), + )) + } + + pub fn to_string(&self) -> String { + format!( + "Color: {:?} RepeatU: {} RepeatV: {} OffsetU: {} OffsetV: {} Rotation: {} Bump: {:?} Shiny: {:?} Fullbright: {} Mapping: {:?} Media: {} Glow: {} ID: {} MaterialID: {} RenderMaterialID: {}", + self.rgba(), + self.repeat_u(), + self.repeat_v(), + self.offset_u(), + self.offset_v(), + self.rotation(), + self.bump(), + self.shiny(), + self.fullbright(), + self.tex_map_type(), + self.media_flags(), + self.glow(), + self.texture_id(), + self.material_id(), + self.render_material_id() + ) + } +} + +#[derive(Debug, PartialEq)] +pub struct PrimitiveTextureEntry { + pub default_texture: Option, + pub face_textures: Vec>, +} + +impl Clone for PrimitiveTextureEntry { + fn clone(&self) -> Self { + let default_texture = self + .default_texture + .as_ref() + .map(PrimitiveTextureEntryFace::deep_clone); + let default_data = default_texture.as_ref().map(|face| face.data.clone()); + let face_textures = self + .face_textures + .iter() + .map(|face| { + face.as_ref() + .map(|face| face.clone_with_default(default_data.clone())) + }) + .collect(); + Self { + default_texture, + face_textures, + } + } +} + +impl PrimitiveTextureEntry { + pub const MAX_FACES: i32 = 45; + pub fn white_texture() -> UUID { + UUID::new_with_string("5748decc-f629-461c-9a36-a35a221fe21f".into()) + .expect("fixed white texture UUID") + } + + fn empty_faces() -> Vec> { + (0..Self::MAX_FACES).map(|_| None).collect() + } + + pub fn new_with_uuid(default_texture_id: UUID) -> Result { + let mut default = PrimitiveTextureEntryFace::default_face(); + default.set_texture_id(default_texture_id); + Ok(Self { + default_texture: Some(default), + face_textures: Self::empty_faces(), + }) + } + + pub fn new_with_texture_entry_face( + default_face: PrimitiveTextureEntryFace, + ) -> Result { + let mut default = PrimitiveTextureEntryFace::default_face(); + default.set_bump(default_face.bump()); + default.set_fullbright(default_face.fullbright()); + default.set_media_flags(default_face.media_flags()); + default.set_offset_u(default_face.offset_u()); + default.set_offset_v(default_face.offset_v()); + default.set_repeat_u(default_face.repeat_u()); + default.set_repeat_v(default_face.repeat_v()); + default.set_rgba(default_face.rgba()); + default.set_rotation(default_face.rotation()); + default.set_glow(default_face.glow()); + default.set_shiny(default_face.shiny()); + default.set_tex_map_type(default_face.tex_map_type()); + default.set_texture_id(default_face.texture_id()); + default.set_material_id(default_face.material_id()); + default.set_render_material_id(default_face.render_material_id()); + Ok(Self { + default_texture: Some(default), + face_textures: Self::empty_faces(), + }) + } + + pub fn new_with_texture_entry(source: Self) -> Result { + Ok(source.clone()) + } + + pub fn create_face(&mut self, index: u32) -> Result<&mut PrimitiveTextureEntryFace, Error> { + let index = usize::try_from(index).map_err(|_| Error::IndexOutOfRange)?; + if index >= Self::MAX_FACES as usize { + return Err(Error::IndexOutOfRange); + } + let default = self + .default_texture + .as_ref() + .ok_or(Error::InvalidOperation)? + .data + .clone(); + if self.face_textures[index].is_none() { + self.face_textures[index] = Some(PrimitiveTextureEntryFace::inheriting(default)); + } + self.face_textures[index] + .as_mut() + .ok_or(Error::InvalidOperation) + } + + pub fn get_face(&self, index: u32) -> Result, Error> { + let index = usize::try_from(index).map_err(|_| Error::IndexOutOfRange)?; + if index >= Self::MAX_FACES as usize { + return Err(Error::IndexOutOfRange); + } + Ok(self.face_textures[index] + .as_ref() + .or(self.default_texture.as_ref())) + } + + pub fn get_osd(&self) -> Result { + let Some(default) = &self.default_texture else { + return Ok(OSD::Array(Vec::new())); + }; + let mut faces = Vec::with_capacity(1 + self.face_textures.iter().flatten().count()); + faces.push(default.get_osd(-1)?); + for (index, face) in self.face_textures.iter().enumerate() { + if let Some(face) = face { + faces.push(face.get_osd(index as i32)?); + } + } + Ok(OSD::Array(faces)) + } + + pub fn from_osd(osd: OSD) -> Result { + let OSD::Array(faces) = osd else { + return Self::new_with_uuid(UUID::zero()); + }; + if faces.is_empty() { + return Self::new_with_uuid(UUID::zero()); + } + if faces.len() > MAX_OSD_FACE_ENTRIES { + return Err(Error::Argument); + } + let mut number = -1; + let default = PrimitiveTextureEntryFace::from_osd(faces[0].clone(), None, &mut number)?; + let mut entry = Self::new_with_texture_entry_face(default)?; + for value in faces.into_iter().skip(1) { + let default = entry + .default_texture + .as_ref() + .ok_or(Error::InvalidOperation)? + .deep_clone(); + let face = PrimitiveTextureEntryFace::from_osd(value, Some(default), &mut number)?; + let index = usize::try_from(number).map_err(|_| Error::IndexOutOfRange)?; + if index < Self::MAX_FACES as usize { + let shared_default = entry + .default_texture + .as_ref() + .ok_or(Error::InvalidOperation)? + .data + .clone(); + entry.face_textures[index] = Some(face.clone_with_default(Some(shared_default))); + } + } + Ok(entry) + } + + pub fn get_hash_code(&self) -> i32 { + self.default_texture + .as_ref() + .map_or(0, PrimitiveTextureEntryFace::get_hash_code) + ^ self + .face_textures + .iter() + .flatten() + .fold(0, |hash, face| hash ^ face.get_hash_code()) + } + pub fn to_string(&self) -> String { + let mut output = format!( + "Default Face: {}\n", + self.default_texture + .as_ref() + .map_or_else(String::new, PrimitiveTextureEntryFace::to_string) + ); + for (index, face) in self.face_textures.iter().enumerate() { + if let Some(face) = face { + let _ = writeln!(output, "Face {index}: {}", face.to_string()); + } + } + output + } + + pub fn new_with_bytes_int32_int32(data: Vec, pos: i32, length: i32) -> Result { + let length = usize::try_from(length).map_err(|_| Error::Argument)?; + if length > MAX_TEXTURE_ENTRY_BYTES { + return Err(Error::Argument); + } + let bytes = checked_window(&data, pos, length)?; + let mut entry = Self::new_with_uuid(UUID::zero())?; + if length < 16 { + return Ok(entry); + } + let mut cursor = 0_usize; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_texture_id(read_uuid(bytes, &mut cursor)?); + decode_overrides(&mut entry, bytes, &mut cursor, 16, |face, bytes| { + face.set_texture_id( + UUID::new_with_bytes_int32(bytes.to_vec(), 0).unwrap_or_else(|_| UUID::zero()), + ); + })?; + let color = read_exact(bytes, &mut cursor, 4)?; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_rgba(Color4::new_with_bytes_int32_boolean( + color.to_vec(), + 0, + true, + )?); + decode_overrides(&mut entry, bytes, &mut cursor, 4, |face, bytes| { + if let Ok(value) = Color4::new_with_bytes_int32_boolean(bytes.to_vec(), 0, true) { + face.set_rgba(value); + } + })?; + let value = read_f32(bytes, cursor)?; + cursor += 4; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_repeat_u(value); + decode_overrides(&mut entry, bytes, &mut cursor, 4, |face, bytes| { + face.set_repeat_u(f32::from_le_bytes(bytes.try_into().unwrap_or([0; 4]))); + })?; + let value = read_f32(bytes, cursor)?; + cursor += 4; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_repeat_v(value); + decode_overrides(&mut entry, bytes, &mut cursor, 4, |face, bytes| { + face.set_repeat_v(f32::from_le_bytes(bytes.try_into().unwrap_or([0; 4]))); + })?; + let value = te_offset_float_slice(read_exact(bytes, &mut cursor, 2)?)?; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_offset_u(value); + decode_overrides(&mut entry, bytes, &mut cursor, 2, |face, bytes| { + if let Ok(value) = te_offset_float_slice(bytes) { + face.set_offset_u(value); + } + })?; + let value = te_offset_float_slice(read_exact(bytes, &mut cursor, 2)?)?; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_offset_v(value); + decode_overrides(&mut entry, bytes, &mut cursor, 2, |face, bytes| { + if let Ok(value) = te_offset_float_slice(bytes) { + face.set_offset_v(value); + } + })?; + let value = te_rotation_float_slice(read_exact(bytes, &mut cursor, 2)?)?; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_rotation(value); + decode_overrides(&mut entry, bytes, &mut cursor, 2, |face, bytes| { + if let Ok(value) = te_rotation_float_slice(bytes) { + face.set_rotation(value); + } + })?; + let value = *read_exact(bytes, &mut cursor, 1)? + .first() + .ok_or(Error::IndexOutOfRange)?; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_material(value); + decode_overrides(&mut entry, bytes, &mut cursor, 1, |face, bytes| { + face.set_material(bytes[0]); + })?; + let value = *read_exact(bytes, &mut cursor, 1)? + .first() + .ok_or(Error::IndexOutOfRange)?; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_media(value); + decode_overrides(&mut entry, bytes, &mut cursor, 1, |face, bytes| { + face.set_media(bytes[0]); + })?; + if cursor >= bytes.len() { + return Ok(entry); + } + let value = f32::from( + *read_exact(bytes, &mut cursor, 1)? + .first() + .ok_or(Error::IndexOutOfRange)?, + ) / 255.0; + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_glow(value); + decode_overrides(&mut entry, bytes, &mut cursor, 1, |face, bytes| { + face.set_glow(f32::from(bytes[0]) / 255.0); + })?; + if bytes.len().saturating_sub(cursor) >= 16 { + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_material_id(read_uuid(bytes, &mut cursor)?); + decode_overrides(&mut entry, bytes, &mut cursor, 16, |face, bytes| { + face.set_material_id( + UUID::new_with_bytes_int32(bytes.to_vec(), 0).unwrap_or_else(|_| UUID::zero()), + ); + })?; + } + if bytes.len().saturating_sub(cursor) >= 16 { + entry + .default_texture + .as_mut() + .ok_or(Error::InvalidOperation)? + .set_render_material_id(read_uuid(bytes, &mut cursor)?); + decode_overrides_optional_terminator( + &mut entry, + bytes, + &mut cursor, + 16, + |face, bytes| { + face.set_render_material_id( + UUID::new_with_bytes_int32(bytes.to_vec(), 0) + .unwrap_or_else(|_| UUID::zero()), + ); + }, + )?; + } + Ok(entry) + } + + pub fn get_bytes(&self) -> Result, Error> { + let Some(default) = &self.default_texture else { + return Ok(Vec::new()); + }; + let mut output = Vec::new(); + output.extend_from_slice(&default.texture_id().get_bytes()?); + encode_face_values( + self, + &mut output, + default.texture_id(), + PrimitiveTextureEntryFace::texture_id, + |value| value.get_bytes(), + true, + )?; + output.extend_from_slice(&default.rgba().get_bytes_with_boolean(true)?); + encode_face_values( + self, + &mut output, + default.rgba(), + PrimitiveTextureEntryFace::rgba, + |value| value.get_bytes_with_boolean(true), + true, + )?; + output.extend_from_slice(&default.repeat_u().to_le_bytes()); + encode_face_values( + self, + &mut output, + default.repeat_u().to_bits(), + |face| face.repeat_u().to_bits(), + |value| Ok(f32::from_bits(value).to_le_bytes().to_vec()), + true, + )?; + output.extend_from_slice(&default.repeat_v().to_le_bytes()); + encode_face_values( + self, + &mut output, + default.repeat_v().to_bits(), + |face| face.repeat_v().to_bits(), + |value| Ok(f32::from_bits(value).to_le_bytes().to_vec()), + true, + )?; + output.extend_from_slice(&te_offset_short(default.offset_u()).to_le_bytes()); + encode_face_values( + self, + &mut output, + te_offset_short(default.offset_u()), + |face| te_offset_short(face.offset_u()), + |value| Ok(value.to_le_bytes().to_vec()), + true, + )?; + output.extend_from_slice(&te_offset_short(default.offset_v()).to_le_bytes()); + encode_face_values( + self, + &mut output, + te_offset_short(default.offset_v()), + |face| te_offset_short(face.offset_v()), + |value| Ok(value.to_le_bytes().to_vec()), + true, + )?; + output.extend_from_slice(&te_rotation_short(default.rotation()).to_le_bytes()); + encode_face_values( + self, + &mut output, + te_rotation_short(default.rotation()), + |face| te_rotation_short(face.rotation()), + |value| Ok(value.to_le_bytes().to_vec()), + true, + )?; + output.push(default.material()); + encode_face_values( + self, + &mut output, + default.material(), + PrimitiveTextureEntryFace::material, + |value| Ok(vec![value]), + true, + )?; + output.push(default.media()); + encode_face_values( + self, + &mut output, + default.media(), + PrimitiveTextureEntryFace::media, + |value| Ok(vec![value]), + true, + )?; + output.push(te_glow_byte(default.glow())); + encode_face_values( + self, + &mut output, + te_glow_byte(default.glow()), + |face| te_glow_byte(face.glow()), + |value| Ok(vec![value]), + true, + )?; + output.extend_from_slice(&default.material_id().get_bytes()?); + encode_face_values( + self, + &mut output, + default.material_id(), + PrimitiveTextureEntryFace::material_id, + |value| value.get_bytes(), + true, + )?; + output.extend_from_slice(&default.render_material_id().get_bytes()?); + encode_face_values( + self, + &mut output, + default.render_material_id(), + PrimitiveTextureEntryFace::render_material_id, + |value| value.get_bytes(), + false, + )?; + if output.len() > MAX_TEXTURE_ENTRY_BYTES { + return Err(Error::Argument); + } + Ok(output) + } +} + +fn read_exact<'a>(data: &'a [u8], cursor: &mut usize, length: usize) -> Result<&'a [u8], Error> { + let end = cursor.checked_add(length).ok_or(Error::IndexOutOfRange)?; + let value = data.get(*cursor..end).ok_or(Error::IndexOutOfRange)?; + *cursor = end; + Ok(value) +} + +fn read_uuid(data: &[u8], cursor: &mut usize) -> Result { + UUID::new_with_bytes_int32(read_exact(data, cursor, 16)?.to_vec(), 0) +} + +fn read_face_bitfield(data: &[u8], cursor: &mut usize) -> Result, Error> { + let mut bits = 0_u64; + for _ in 0..10 { + let byte = *read_exact(data, cursor, 1)? + .first() + .ok_or(Error::IndexOutOfRange)?; + bits = bits.checked_shl(7).ok_or(Error::Argument)? | u64::from(byte & 0x7f); + if byte & 0x80 == 0 { + if bits >> PrimitiveTextureEntry::MAX_FACES != 0 { + return Err(Error::Argument); + } + return Ok((bits != 0).then_some(bits)); + } + } + Err(Error::Argument) +} + +fn face_bitfield_bytes(bits: u64) -> Vec { + if bits == 0 { + return vec![0]; + } + let chunks = (64 - bits.leading_zeros() as usize).div_ceil(7); + (0..chunks) + .map(|index| { + let shift = 7 * (chunks - index - 1); + ((bits >> shift) as u8 & 0x7f) | if index + 1 < chunks { 0x80 } else { 0 } + }) + .collect() +} + +fn decode_overrides( + entry: &mut PrimitiveTextureEntry, + data: &[u8], + cursor: &mut usize, + value_size: usize, + mut set: impl FnMut(&mut PrimitiveTextureEntryFace, &[u8]), +) -> Result<(), Error> { + while let Some(bits) = read_face_bitfield(data, cursor)? { + let value = read_exact(data, cursor, value_size)?; + for face in 0..PrimitiveTextureEntry::MAX_FACES as usize { + if bits & (1_u64 << face) != 0 { + set(entry.create_face(face as u32)?, value); + } + } + } + Ok(()) +} + +fn decode_overrides_optional_terminator( + entry: &mut PrimitiveTextureEntry, + data: &[u8], + cursor: &mut usize, + value_size: usize, + mut set: impl FnMut(&mut PrimitiveTextureEntryFace, &[u8]), +) -> Result<(), Error> { + while *cursor < data.len() { + let Some(bits) = read_face_bitfield(data, cursor)? else { + break; + }; + let value = read_exact(data, cursor, value_size)?; + for face in 0..PrimitiveTextureEntry::MAX_FACES as usize { + if bits & (1_u64 << face) != 0 { + set(entry.create_face(face as u32)?, value); + } + } + } + Ok(()) +} + +fn encode_face_values( + entry: &PrimitiveTextureEntry, + output: &mut Vec, + default: T, + get: impl Fn(&PrimitiveTextureEntryFace) -> T, + bytes: impl Fn(T) -> Result, Error>, + terminator: bool, +) -> Result<(), Error> { + for (index, face) in entry.face_textures.iter().enumerate() { + if let Some(face) = face { + let value = get(face); + if value != default { + output.extend_from_slice(&face_bitfield_bytes(1_u64 << index)); + output.extend_from_slice(&bytes(value)?); + } + } + } + if terminator { + output.push(0); + } + Ok(()) +} + +pub(crate) fn te_offset_short(offset: f32) -> i16 { + (offset.clamp(-1.0, 1.0) * 32767.0).round_ties_even() as i16 +} +fn te_offset_float_slice(bytes: &[u8]) -> Result { + Ok(f32::from(i16::from_le_bytes( + bytes.try_into().map_err(|_| Error::IndexOutOfRange)?, + )) / 32767.0) +} +pub(crate) fn te_offset_float(bytes: Vec, pos: i32) -> Result { + te_offset_float_slice(checked_window(&bytes, pos, 2)?) +} +pub(crate) fn te_rotation_short(rotation: f32) -> i16 { + let two_pi = f64::from(std::f32::consts::TAU); + let rotation = f64::from(rotation); + let remainder = rotation - (rotation / two_pi).round_ties_even() * two_pi; + (remainder / two_pi * 32768.0).round_ties_even() as i16 +} +fn te_rotation_float_slice(bytes: &[u8]) -> Result { + Ok(f32::from(u16::from_le_bytes( + bytes.try_into().map_err(|_| Error::IndexOutOfRange)?, + )) / 32768.0 + * std::f32::consts::TAU) +} +pub(crate) fn te_rotation_float(bytes: Vec, pos: i32) -> Result { + te_rotation_float_slice(checked_window(&bytes, pos, 2)?) +} +pub(crate) fn te_glow_byte(glow: f32) -> u8 { + (glow.clamp(0.0, 1.0) * 255.0) as u8 +} +pub(crate) fn te_glow_float(bytes: Vec, pos: i32) -> Result { + Ok(f32::from( + *checked_window(&bytes, pos, 1)? + .first() + .ok_or(Error::IndexOutOfRange)?, + ) / 255.0) +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimitiveParticleSystem { + pub angular_velocity: Vector3, + pub blend_func_dest: u8, + pub blend_func_source: u8, + pub burst_part_count: u8, + pub burst_radius: f32, + pub burst_rate: f32, + pub burst_speed_max: f32, + pub burst_speed_min: f32, + pub crc: u32, + pub inner_angle: f32, + pub max_age: f32, + pub outer_angle: f32, + pub part_acceleration: Vector3, + pub part_data_flags: PrimitiveParticleSystemParticleDataFlags, + pub part_end_color: Color4, + pub part_end_glow: f32, + pub part_end_scale_x: f32, + pub part_end_scale_y: f32, + pub part_flags: u32, + pub part_max_age: f32, + pub part_start_color: Color4, + pub part_start_glow: f32, + pub part_start_scale_x: f32, + pub part_start_scale_y: f32, + pub pattern: PrimitiveParticleSystemSourcePattern, + pub start_age: f32, + pub target: UUID, + pub texture: UUID, +} + +impl Default for PrimitiveParticleSystem { + fn default() -> Self { + Self { + angular_velocity: Vector3::zero(), + blend_func_dest: PrimitiveParticleSystemBlendFunc::OneMinusSourceAlpha as u8, + blend_func_source: PrimitiveParticleSystemBlendFunc::SourceAlpha as u8, + burst_part_count: 0, + burst_radius: 0.0, + burst_rate: 0.0, + burst_speed_max: 0.0, + burst_speed_min: 0.0, + crc: 0, + inner_angle: 0.0, + max_age: 0.0, + outer_angle: 0.0, + part_acceleration: Vector3::zero(), + part_data_flags: PrimitiveParticleSystemParticleDataFlags::NONE, + part_end_color: Color4::black(), + part_end_glow: 0.0, + part_end_scale_x: 0.0, + part_end_scale_y: 0.0, + part_flags: 0, + part_max_age: 0.0, + part_start_color: Color4::black(), + part_start_glow: 0.0, + part_start_scale_x: 0.0, + part_start_scale_y: 0.0, + pattern: PrimitiveParticleSystemSourcePattern::NONE, + start_age: 0.0, + target: UUID::zero(), + texture: UUID::zero(), + } + } +} + +impl PrimitiveParticleSystem { + pub const LEGACY_DATA_BLOCK_SIZE: u8 = 86; + pub const MAX_DATA_BLOCK_SIZE: u8 = 98; + pub const PART_DATA_SIZE: u8 = 18; + pub const SYS_DATA_SIZE: u8 = 68; + + pub fn new(data: Vec, pos: i32) -> Result { + let start = usize::try_from(pos).map_err(|_| Error::IndexOutOfRange)?; + let size = data + .len() + .checked_sub(start) + .ok_or(Error::IndexOutOfRange)?; + if size > usize::from(Self::MAX_DATA_BLOCK_SIZE) { + return Err(Error::Argument); + } + if size != usize::from(Self::LEGACY_DATA_BLOCK_SIZE) && size < 94 { + return Err(Error::Argument); + } + let slice = data.get(start..).ok_or(Error::IndexOutOfRange)?.to_vec(); + let mut pack = BitPack::new(slice, 0)?; + let mut value = Self::default(); + if size == usize::from(Self::LEGACY_DATA_BLOCK_SIZE) { + value.unpack_system(&mut pack)?; + value.unpack_legacy(&mut pack)?; + return Ok(value); + } + let system_size = pack.unpack_u_bits(32)?; + if system_size != u32::from(Self::SYS_DATA_SIZE) { + return Err(Error::Argument); + } + value.unpack_system(&mut pack)?; + let part_size = pack.unpack_u_bits(32)?; + if !(u32::from(Self::PART_DATA_SIZE)..=u32::from(Self::PART_DATA_SIZE) + 4) + .contains(&part_size) + { + return Err(Error::Argument); + } + let expected = usize::from(Self::SYS_DATA_SIZE) + + usize::try_from(part_size).map_err(|_| Error::Argument)? + + 8; + if expected != size { + return Err(Error::Argument); + } + value.unpack_legacy(&mut pack)?; + if value.part_data_flags.0 & PrimitiveParticleSystemParticleDataFlags::DATA_GLOW.0 != 0 { + value.part_start_glow = f32::from(pack.unpack_byte()?) / 255.0; + value.part_end_glow = f32::from(pack.unpack_byte()?) / 255.0; + } + if value.part_data_flags.0 & PrimitiveParticleSystemParticleDataFlags::DATA_BLEND.0 != 0 { + value.blend_func_source = pack.unpack_byte()?; + value.blend_func_dest = pack.unpack_byte()?; + } + Ok(value) + } + + fn unpack_system(&mut self, pack: &mut BitPack) -> Result<(), Error> { + self.crc = pack.unpack_u_bits(32)?; + self.part_flags = pack.unpack_u_bits(32)?; + self.pattern = PrimitiveParticleSystemSourcePattern(pack.unpack_byte()?); + self.max_age = pack.unpack_fixed(false, 8, 8)?; + self.start_age = pack.unpack_fixed(false, 8, 8)?; + self.inner_angle = pack.unpack_fixed(false, 3, 5)?; + self.outer_angle = pack.unpack_fixed(false, 3, 5)?; + self.burst_rate = pack.unpack_fixed(false, 8, 8)?; + self.burst_radius = pack.unpack_fixed(false, 8, 8)?; + self.burst_speed_min = pack.unpack_fixed(false, 8, 8)?; + self.burst_speed_max = pack.unpack_fixed(false, 8, 8)?; + self.burst_part_count = pack.unpack_byte()?; + self.angular_velocity = Vector3 { + x: pack.unpack_fixed(true, 8, 7)?, + y: pack.unpack_fixed(true, 8, 7)?, + z: pack.unpack_fixed(true, 8, 7)?, + }; + self.part_acceleration = Vector3 { + x: pack.unpack_fixed(true, 8, 7)?, + y: pack.unpack_fixed(true, 8, 7)?, + z: pack.unpack_fixed(true, 8, 7)?, + }; + self.texture = pack.unpack_uuid()?; + self.target = pack.unpack_uuid()?; + Ok(()) + } + + fn unpack_legacy(&mut self, pack: &mut BitPack) -> Result<(), Error> { + self.part_data_flags = PrimitiveParticleSystemParticleDataFlags(pack.unpack_u_bits(32)?); + self.part_max_age = pack.unpack_fixed(false, 8, 8)?; + self.part_start_color = unpack_color(pack)?; + self.part_end_color = unpack_color(pack)?; + self.part_start_scale_x = pack.unpack_fixed(false, 3, 5)?; + self.part_start_scale_y = pack.unpack_fixed(false, 3, 5)?; + self.part_end_scale_x = pack.unpack_fixed(false, 3, 5)?; + self.part_end_scale_y = pack.unpack_fixed(false, 3, 5)?; + Ok(()) + } + + fn pack_system(&self, pack: &mut BitPack) -> Result<(), Error> { + pack.pack_bits_with_u_int32_int32(self.crc, 32)?; + pack.pack_bits_with_u_int32_int32(self.part_flags, 32)?; + pack.pack_bits_with_u_int32_int32(u32::from(self.pattern.0), 8)?; + pack.pack_fixed(self.max_age, false, 8, 8)?; + pack.pack_fixed(self.start_age, false, 8, 8)?; + pack.pack_fixed(self.inner_angle, false, 3, 5)?; + pack.pack_fixed(self.outer_angle, false, 3, 5)?; + pack.pack_fixed(self.burst_rate, false, 8, 8)?; + pack.pack_fixed(self.burst_radius, false, 8, 8)?; + pack.pack_fixed(self.burst_speed_min, false, 8, 8)?; + pack.pack_fixed(self.burst_speed_max, false, 8, 8)?; + pack.pack_bits_with_u_int32_int32(u32::from(self.burst_part_count), 8)?; + pack.pack_fixed(self.angular_velocity.x, true, 8, 7)?; + pack.pack_fixed(self.angular_velocity.y, true, 8, 7)?; + pack.pack_fixed(self.angular_velocity.z, true, 8, 7)?; + pack.pack_fixed(self.part_acceleration.x, true, 8, 7)?; + pack.pack_fixed(self.part_acceleration.y, true, 8, 7)?; + pack.pack_fixed(self.part_acceleration.z, true, 8, 7)?; + pack.pack_uuid(self.texture)?; + pack.pack_uuid(self.target)?; + Ok(()) + } + + fn pack_legacy(&self, pack: &mut BitPack, flags: u32) -> Result<(), Error> { + pack.pack_bits_with_u_int32_int32(flags, 32)?; + pack.pack_fixed(self.part_max_age, false, 8, 8)?; + pack.pack_color(self.part_start_color)?; + pack.pack_color(self.part_end_color)?; + pack.pack_fixed(self.part_start_scale_x, false, 3, 5)?; + pack.pack_fixed(self.part_start_scale_y, false, 3, 5)?; + pack.pack_fixed(self.part_end_scale_x, false, 3, 5)?; + pack.pack_fixed(self.part_end_scale_y, false, 3, 5)?; + Ok(()) + } + + pub fn has_glow(&self) -> Result { + Ok(self.part_start_glow > 0.0 || self.part_end_glow > 0.0) + } + pub fn has_blend_func(&self) -> Result { + Ok( + self.blend_func_source != PrimitiveParticleSystemBlendFunc::SourceAlpha as u8 + || self.blend_func_dest + != PrimitiveParticleSystemBlendFunc::OneMinusSourceAlpha as u8, + ) + } + pub fn is_legacy_compatible(&self) -> Result { + Ok(!self.has_glow()? && !self.has_blend_func()?) + } + + pub fn get_bytes(&self) -> Result, Error> { + let glow = self.has_glow()?; + let blend = self.has_blend_func()?; + let legacy = !glow && !blend; + let size = usize::from(Self::LEGACY_DATA_BLOCK_SIZE) + + if legacy { 0 } else { 8 } + + if glow { 2 } else { 0 } + + if blend { 2 } else { 0 }; + let mut pack = BitPack::new(vec![0_u8; size], 0)?; + let mut flags = self.part_data_flags.0; + if legacy { + self.pack_system(&mut pack)?; + self.pack_legacy(&mut pack, flags)?; + } else { + if glow { + flags |= PrimitiveParticleSystemParticleDataFlags::DATA_GLOW.0; + } + if blend { + flags |= PrimitiveParticleSystemParticleDataFlags::DATA_BLEND.0; + } + pack.pack_bits_with_u_int32_int32(u32::from(Self::SYS_DATA_SIZE), 32)?; + self.pack_system(&mut pack)?; + let part_size = + u32::from(Self::PART_DATA_SIZE) + u32::from(glow) * 2 + u32::from(blend) * 2; + pack.pack_bits_with_u_int32_int32(part_size, 32)?; + self.pack_legacy(&mut pack, flags)?; + if glow { + pack.pack_bits_with_u_int32_int32( + u32::from(te_glow_byte(self.part_start_glow)), + 8, + )?; + pack.pack_bits_with_u_int32_int32(u32::from(te_glow_byte(self.part_end_glow)), 8)?; + } + if blend { + pack.pack_bits_with_u_int32_int32(u32::from(self.blend_func_source), 8)?; + pack.pack_bits_with_u_int32_int32(u32::from(self.blend_func_dest), 8)?; + } + } + Ok(pack.data) + } + + pub fn get_osd(&self) -> Result { + let mut values = HashMap::from([ + ("crc".into(), OSD::from_u_integer(self.crc)?), + ("part_flags".into(), OSD::from_u_integer(self.part_flags)?), + ("pattern".into(), OSD::Integer(i32::from(self.pattern.0))), + ("max_age".into(), OSD::Real(f64::from(self.max_age))), + ("start_age".into(), OSD::Real(f64::from(self.start_age))), + ("inner_angle".into(), OSD::Real(f64::from(self.inner_angle))), + ("outer_angle".into(), OSD::Real(f64::from(self.outer_angle))), + ("burst_rate".into(), OSD::Real(f64::from(self.burst_rate))), + ( + "burst_radius".into(), + OSD::Real(f64::from(self.burst_radius)), + ), + ( + "burst_speed_min".into(), + OSD::Real(f64::from(self.burst_speed_min)), + ), + ( + "burst_speed_max".into(), + OSD::Real(f64::from(self.burst_speed_max)), + ), + ( + "burst_part_count".into(), + OSD::Integer(i32::from(self.burst_part_count)), + ), + ( + "ang_velocity".into(), + OSD::from_vector3(self.angular_velocity)?, + ), + ( + "part_acceleration".into(), + OSD::from_vector3(self.part_acceleration)?, + ), + ("texture".into(), OSD::UUID(self.texture)), + ("target".into(), OSD::UUID(self.target)), + ( + "part_data_flags".into(), + OSD::from_u_integer(self.part_data_flags.0)?, + ), + ( + "part_max_age".into(), + OSD::Real(f64::from(self.part_max_age)), + ), + ( + "part_start_color".into(), + OSD::from_color4(self.part_start_color)?, + ), + ( + "part_end_color".into(), + OSD::from_color4(self.part_end_color)?, + ), + ( + "part_start_scale".into(), + OSD::from_vector3(Vector3 { + x: self.part_start_scale_x, + y: self.part_start_scale_y, + z: 0.0, + })?, + ), + ( + "part_end_scale".into(), + OSD::from_vector3(Vector3 { + x: self.part_end_scale_x, + y: self.part_end_scale_y, + z: 0.0, + })?, + ), + ]); + if self.has_glow()? { + values.insert( + "part_start_glow".into(), + OSD::Real(f64::from(self.part_start_glow)), + ); + values.insert( + "part_end_glow".into(), + OSD::Real(f64::from(self.part_end_glow)), + ); + } + if self.has_blend_func()? { + values.insert( + "blendfunc_source".into(), + OSD::Integer(i32::from(self.blend_func_source)), + ); + values.insert( + "blendfunc_dest".into(), + OSD::Integer(i32::from(self.blend_func_dest)), + ); + } + Ok(OSD::Map(values)) + } + + pub fn from_osd(osd: OSD) -> Result { + let Some(values) = map(osd) else { + return Ok(Self::default()); + }; + let values = Some(&values); + let start_scale = map_vector3(values, "part_start_scale", Vector3::zero()); + let end_scale = map_vector3(values, "part_end_scale", Vector3::zero()); + Ok(Self { + crc: map_u32(values, "crc", 0), + part_flags: map_u32(values, "part_flags", 0), + pattern: PrimitiveParticleSystemSourcePattern(map_i32(values, "pattern", 0) as u8), + max_age: map_real(values, "max_age", 0.0), + start_age: map_real(values, "start_age", 0.0), + inner_angle: map_real(values, "inner_angle", 0.0), + outer_angle: map_real(values, "outer_angle", 0.0), + burst_rate: map_real(values, "burst_rate", 0.0), + burst_radius: map_real(values, "burst_radius", 0.0), + burst_speed_min: map_real(values, "burst_speed_min", 0.0), + burst_speed_max: map_real(values, "burst_speed_max", 0.0), + burst_part_count: map_i32(values, "burst_part_count", 0) as u8, + angular_velocity: map_vector3(values, "ang_velocity", Vector3::zero()), + part_acceleration: map_vector3(values, "part_acceleration", Vector3::zero()), + texture: map_uuid(values, "texture", UUID::zero()), + target: map_uuid(values, "target", UUID::zero()), + part_data_flags: PrimitiveParticleSystemParticleDataFlags(map_u32( + values, + "part_data_flags", + 0, + )), + part_max_age: map_real(values, "part_max_age", 0.0), + part_start_color: values + .and_then(|m| m.get("part_start_color")) + .and_then(|v| v.as_color4().ok()) + .unwrap_or_else(Color4::black), + part_end_color: values + .and_then(|m| m.get("part_end_color")) + .and_then(|v| v.as_color4().ok()) + .unwrap_or_else(Color4::black), + part_start_scale_x: start_scale.x, + part_start_scale_y: start_scale.y, + part_end_scale_x: end_scale.x, + part_end_scale_y: end_scale.y, + part_start_glow: map_real(values, "part_start_glow", 0.0), + part_end_glow: map_real(values, "part_end_glow", 0.0), + blend_func_source: map_i32( + values, + "blendfunc_source", + PrimitiveParticleSystemBlendFunc::SourceAlpha as i32, + ) as u8, + blend_func_dest: map_i32( + values, + "blendfunc_dest", + PrimitiveParticleSystemBlendFunc::OneMinusSourceAlpha as i32, + ) as u8, + }) + } + + pub fn equals_with_particle_system(&self, other: Self) -> bool { + *self == other + } + pub fn equals_with_object(&self, obj: Option) -> bool { + obj.as_ref() + .and_then(Object::downcast_ref::) + .is_some_and(|other| self == other) + } + pub fn get_hash_code(&self) -> i32 { + hash_i32(&self.get_bytes().unwrap_or_default()) + } +} + +fn unpack_color(pack: &mut BitPack) -> Result { + Color4::new_with_byte_byte_byte_byte( + pack.unpack_byte()?, + pack.unpack_byte()?, + pack.unpack_byte()?, + pack.unpack_byte()?, + ) +} + +pub struct Primitive { + pub acceleration: Vector3, + pub active_clients: i32, + pub angular_velocity: Vector3, + pub crc: u32, + pub child_count: i32, + pub click_action: ClickAction, + pub collision_plane: Vector4, + pub extended_mesh_flags: u32, + pub face_media: Vec, + pub flags: PrimFlags, + pub flexible: Option, + pub group_id: UUID, + pub id: UUID, + pub is_attachment: bool, + pub joint: JointType, + pub joint_axis_or_anchor: Vector3, + pub joint_pivot: Vector3, + pub light: Option, + pub light_map: Option, + pub local_id: u32, + pub media_url: String, + pub media_version: String, + pub name_values: Option>, + pub owner_id: UUID, + pub parent_id: u32, + pub particle_sys: PrimitiveParticleSystem, + pub physics_props: Option, + pub position: Vector3, + pub prim_data: PrimitiveConstructionData, + pub properties: Option, + pub region_handle: u64, + pub rotation: Quaternion, + pub scale: Vector3, + pub scratch_pad: Vec, + pub sculpt: Option, + pub signaled_animations: Option>, + pub sound: UUID, + pub sound_flags: SoundFlags, + pub sound_gain: f32, + pub sound_radius: f32, + pub tag: Option, + pub text: String, + pub text_color: Color4, + pub texture_anim: PrimitiveTextureAnimation, + pub textures: Option, + pub tree_species: Tree, + pub velocity: Vector3, + pub(crate) unknown_extra_params: Vec<(u16, Vec)>, +} + +impl std::fmt::Debug for Primitive { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter + .debug_struct("Primitive") + .field("id", &self.id) + .field("local_id", &self.local_id) + .field("type", &self.type_()) + .finish_non_exhaustive() + } +} + +impl Clone for Primitive { + fn clone(&self) -> Self { + Self { + acceleration: self.acceleration, + active_clients: self.active_clients, + angular_velocity: self.angular_velocity, + crc: self.crc, + child_count: self.child_count, + click_action: self.click_action, + collision_plane: self.collision_plane, + extended_mesh_flags: self.extended_mesh_flags, + face_media: self.face_media.clone(), + flags: self.flags, + flexible: self.flexible.clone(), + group_id: self.group_id, + id: self.id, + is_attachment: self.is_attachment, + joint: self.joint, + joint_axis_or_anchor: self.joint_axis_or_anchor, + joint_pivot: self.joint_pivot, + light: self.light.clone(), + light_map: self.light_map.clone(), + local_id: self.local_id, + media_url: self.media_url.clone(), + media_version: self.media_version.clone(), + name_values: self + .name_values + .as_ref() + .map(|values| values.iter().map(clone_name_value).collect()), + owner_id: self.owner_id, + parent_id: self.parent_id, + particle_sys: self.particle_sys.clone(), + physics_props: self.physics_props.clone(), + position: self.position, + prim_data: self.prim_data.clone(), + properties: self.properties.clone(), + region_handle: self.region_handle, + rotation: self.rotation, + scale: self.scale, + scratch_pad: self.scratch_pad.clone(), + sculpt: self.sculpt.clone(), + signaled_animations: self.signaled_animations.clone(), + sound: self.sound, + sound_flags: self.sound_flags, + sound_gain: self.sound_gain, + sound_radius: self.sound_radius, + tag: self.tag.clone(), + text: self.text.clone(), + text_color: self.text_color, + texture_anim: self.texture_anim, + textures: self.textures.clone(), + tree_species: self.tree_species, + velocity: self.velocity, + unknown_extra_params: self.unknown_extra_params.clone(), + } + } +} + +fn clone_name_value(value: &NameValue) -> NameValue { + NameValue { + class_: value.class_, + name: value.name.clone(), + sendto: value.sendto, + type_: value.type_, + value: value.value.clone(), + } +} + +impl Primitive { + pub fn new_with_constructor() -> Result { + Ok(crate::current_outfit::primitive_defaults()) + } + pub fn new_with_primitive(prim: Self) -> Result { + Ok(prim.clone()) + } + pub fn equals_with_primitive(&self, other: Option) -> bool { + other.is_some_and(|value| self.id == value.id) + } + pub fn equals_with_object(&self, obj: Option) -> bool { + obj.as_ref() + .and_then(Object::downcast_ref::) + .is_some_and(|other| self.id == other.id) + } + pub fn eq(lhs: Option, rhs: Option) -> bool { + match (lhs, rhs) { + (None, None) => true, + (Some(left), Some(right)) => left.id == right.id, + _ => false, + } + } + pub fn ne(lhs: Option, rhs: Option) -> bool { + !Self::eq(lhs, rhs) + } + + pub fn get_children( + &self, + client: crate::GridClient, + ) -> Result>, Error> { + let Some(simulator) = client + .native_network()? + .find_simulator_with_u_int64(self.region_handle)? + else { + return Ok(Box::new(std::iter::empty())); + }; + let children = simulator + .objects_primitives + .read() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .values() + .filter(|primitive| primitive.parent_id == self.local_id) + .cloned() + .collect::>(); + Ok(Box::new(children.into_iter())) + } + + pub fn grass_species(&self) -> Grass { + grass_from_u8(self.prim_data.state) + } + pub fn set_grass_species(&mut self, value: Grass) { + self.prim_data.state = value as u8; + } + pub fn get_grass_definition(&self) -> Result { + crate::foliage_catalog::grass_by_id(self.prim_data.state) + } + pub fn get_tree_definition(&self) -> Result { + crate::foliage_catalog::TreeDefinitions::get(self.tree_species) + } + pub fn is_animated_object(&self) -> bool { + self.extended_mesh_flags & 1 != 0 + } + + pub fn type_(&self) -> PrimType { + if let Some(sculpt) = &self.sculpt + && sculpt.type_() != SculptType::None + && sculpt.sculpt_texture != UUID::zero() + { + return if sculpt.type_() == SculptType::Mesh { + PrimType::Mesh + } else { + PrimType::Sculpt + }; + } + let profile = self.prim_data.profile_curve_with_property(); + if matches!( + self.prim_data.path_curve, + PathCurve::Line | PathCurve::Flexible + ) { + return match profile { + ProfileCurve::Circle => PrimType::Cylinder, + ProfileCurve::Square => PrimType::Box, + ProfileCurve::IsoTriangle + | ProfileCurve::EqualTriangle + | ProfileCurve::RightTriangle => PrimType::Prism, + ProfileCurve::HalfCircle => PrimType::Unknown, + }; + } + match self.prim_data.path_curve { + PathCurve::Circle => match profile { + ProfileCurve::Circle => { + if self.prim_data.path_scale_y > 0.75 { + PrimType::Sphere + } else { + PrimType::Torus + } + } + ProfileCurve::HalfCircle => PrimType::Sphere, + ProfileCurve::EqualTriangle => PrimType::Ring, + ProfileCurve::Square if self.prim_data.path_scale_y <= 0.75 => PrimType::Tube, + _ => PrimType::Unknown, + }, + PathCurve::Circle2 if profile == ProfileCurve::Circle => PrimType::Sphere, + _ => PrimType::Unknown, + } + } + + pub fn get_osd(&self) -> Result { + let path = OSD::Map(HashMap::from([ + ( + "begin".into(), + OSD::Real(f64::from(self.prim_data.path_begin)), + ), + ( + "curve".into(), + OSD::Integer(self.prim_data.path_curve as i32), + ), + ("end".into(), OSD::Real(f64::from(self.prim_data.path_end))), + ( + "radius_offset".into(), + OSD::Real(f64::from(self.prim_data.path_radius_offset)), + ), + ( + "revolutions".into(), + OSD::Real(f64::from(self.prim_data.path_revolutions)), + ), + ( + "scale_x".into(), + OSD::Real(f64::from(self.prim_data.path_scale_x)), + ), + ( + "scale_y".into(), + OSD::Real(f64::from(self.prim_data.path_scale_y)), + ), + ( + "shear_x".into(), + OSD::Real(f64::from(self.prim_data.path_shear_x)), + ), + ( + "shear_y".into(), + OSD::Real(f64::from(self.prim_data.path_shear_y)), + ), + ( + "skew".into(), + OSD::Real(f64::from(self.prim_data.path_skew)), + ), + ( + "taper_x".into(), + OSD::Real(f64::from(self.prim_data.path_taper_x)), + ), + ( + "taper_y".into(), + OSD::Real(f64::from(self.prim_data.path_taper_y)), + ), + ( + "twist".into(), + OSD::Real(f64::from(self.prim_data.path_twist)), + ), + ( + "twist_begin".into(), + OSD::Real(f64::from(self.prim_data.path_twist_begin)), + ), + ])); + let profile = OSD::Map(HashMap::from([ + ( + "begin".into(), + OSD::Real(f64::from(self.prim_data.profile_begin)), + ), + ( + "curve".into(), + OSD::Integer(self.prim_data.profile_curve_with_property() as i32), + ), + ( + "hole".into(), + OSD::Integer(i32::from(self.prim_data.profile_hole().0)), + ), + ( + "end".into(), + OSD::Real(f64::from(self.prim_data.profile_end)), + ), + ( + "hollow".into(), + OSD::Real(f64::from(self.prim_data.profile_hollow)), + ), + ])); + let (name, description) = self.properties.as_ref().map_or_else( + || ("Object".to_owned(), String::new()), + |value| (value.name.clone(), value.description.clone()), + ); + let mut values = HashMap::from([ + ("name".into(), OSD::String(name)), + ("description".into(), OSD::String(description)), + ( + "phantom".into(), + OSD::Boolean(self.flags.0 & PrimFlags::PHANTOM.0 != 0), + ), + ( + "physical".into(), + OSD::Boolean(self.flags.0 & PrimFlags::PHYSICS.0 != 0), + ), + ("position".into(), OSD::from_vector3(self.position)?), + ("rotation".into(), OSD::from_quaternion(self.rotation)?), + ("scale".into(), OSD::from_vector3(self.scale)?), + ("pcode".into(), OSD::Integer(self.prim_data.p_code as i32)), + ( + "material".into(), + OSD::Integer(self.prim_data.material as i32), + ), + ( + "shadows".into(), + OSD::Boolean(self.flags.0 & PrimFlags::CAST_SHADOWS.0 != 0), + ), + ( + "state".into(), + OSD::Integer(i32::from(self.prim_data.state)), + ), + ("id".into(), OSD::UUID(self.id)), + ("localid".into(), OSD::from_u_integer(self.local_id)?), + ("parentid".into(), OSD::from_u_integer(self.parent_id)?), + ( + "volume".into(), + OSD::Map(HashMap::from([ + ("path".into(), path), + ("profile".into(), profile), + ])), + ), + ]); + if let Some(value) = &self.textures { + values.insert("textures".into(), value.get_osd()?); + } + if self.texture_anim.flags.0 & PrimitiveTextureAnimMode::ANIM_ON.0 != 0 { + values.insert("texture_anim".into(), self.texture_anim.get_osd()?); + } + if let Some(value) = &self.light { + values.insert("light".into(), value.get_osd()?); + } + if let Some(value) = &self.light_map { + values.insert("light_image".into(), value.get_osd()?); + } + if let Some(value) = &self.flexible { + values.insert("flex".into(), value.get_osd()?); + } + if let Some(value) = &self.sculpt { + values.insert("sculpt".into(), value.get_osd()?); + } + Ok(OSD::Map(values)) + } + + pub fn from_osd(osd: OSD) -> Result { + let mut primitive = Self::new_with_constructor()?; + let Some(values) = map(osd) else { + return Ok(primitive); + }; + let volume = values.get("volume").and_then(|value| { + if let OSD::Map(map) = value { + Some(map) + } else { + None + } + }); + let path = volume.and_then(|map| map.get("path")).and_then(|value| { + if let OSD::Map(map) = value { + Some(map) + } else { + None + } + }); + let profile = volume.and_then(|map| map.get("profile")).and_then(|value| { + if let OSD::Map(map) = value { + Some(map) + } else { + None + } + }); + let mut data = PrimitiveConstructionData::default(); + data.material = + material_from_i32(map_i32(Some(&values), "material", Material::Stone as i32)); + data.p_code = pcode_from_i32(map_i32(Some(&values), "pcode", PCode::Prim as i32)); + data.state = map_i32(Some(&values), "state", 0) as u8; + data.path_begin = map_real(path, "begin", 0.0); + data.path_curve = path_curve_from_i32(map_i32(path, "curve", PathCurve::Line as i32)); + data.path_end = map_real(path, "end", 1.0); + data.path_radius_offset = map_real(path, "radius_offset", 0.0); + data.path_revolutions = map_real(path, "revolutions", 1.0); + data.path_scale_x = map_real(path, "scale_x", 1.0); + data.path_scale_y = map_real(path, "scale_y", 1.0); + data.path_shear_x = map_real(path, "shear_x", 0.0); + data.path_shear_y = map_real(path, "shear_y", 0.0); + data.path_skew = map_real(path, "skew", 0.0); + data.path_taper_x = map_real(path, "taper_x", 0.0); + data.path_taper_y = map_real(path, "taper_y", 0.0); + data.path_twist = map_real(path, "twist", 0.0); + data.path_twist_begin = map_real(path, "twist_begin", 0.0); + data.profile_begin = map_real(profile, "begin", 0.0); + data.profile_end = map_real(profile, "end", 1.0); + data.profile_hollow = map_real(profile, "hollow", 0.0); + data.set_profile_curve_with_property(profile_curve_from_u8(map_i32( + profile, + "curve", + ProfileCurve::Circle as i32, + ) as u8)); + data.set_profile_hole(HoleType(map_i32(profile, "hole", 0) as u8)); + primitive.prim_data = data; + primitive.flags = PrimFlags::NONE; + if map_bool(Some(&values), "phantom", false) { + primitive.flags.0 |= PrimFlags::PHANTOM.0; + } + if map_bool(Some(&values), "physical", false) { + primitive.flags.0 |= PrimFlags::PHYSICS.0; + } + if map_bool(Some(&values), "shadows", false) { + primitive.flags.0 |= PrimFlags::CAST_SHADOWS.0; + } + primitive.id = map_uuid(Some(&values), "id", UUID::zero()); + primitive.local_id = map_u32(Some(&values), "localid", 0); + primitive.parent_id = map_u32(Some(&values), "parentid", 0); + primitive.position = map_vector3(Some(&values), "position", Vector3::zero()); + primitive.scale = map_vector3(Some(&values), "scale", Vector3::one()); + primitive.rotation = values + .get("rotation") + .filter(|value| matches!(value, OSD::Array(items) if items.len() == 4)) + .and_then(|value| value.as_quaternion().ok()) + .unwrap_or_else(Quaternion::identity); + if let Some(value) = values.get("flex") { + primitive.flexible = Some(PrimitiveFlexibleData::from_osd(value.clone())?); + } + if let Some(value) = values.get("light") { + primitive.light = Some(PrimitiveLightData::from_osd(value.clone())?); + } + if let Some(value) = values.get("light_image") { + primitive.light_map = Some(PrimitiveLightImage::from_osd(value.clone())?); + } + if let Some(value) = values.get("sculpt") { + primitive.sculpt = Some(PrimitiveSculptData::from_osd(value.clone())?); + } + if let Some(value) = values.get("textures") { + primitive.textures = Some(PrimitiveTextureEntry::from_osd(value.clone())?); + } + if let Some(value) = values.get("texture_anim") { + primitive.texture_anim = PrimitiveTextureAnimation::from_osd(value.clone())?; + } + let mut properties = PrimitiveObjectProperties::default(); + properties.name = values + .get("name") + .and_then(|v| v.as_string().ok()) + .unwrap_or_default(); + properties.description = values + .get("description") + .and_then(|v| v.as_string().ok()) + .unwrap_or_default(); + primitive.properties = Some(properties); + Ok(primitive) + } + + pub fn set_extra_params_from_bytes(&mut self, data: Vec, pos: i32) -> Result { + let start = usize::try_from(pos).map_err(|_| Error::IndexOutOfRange)?; + let mut cursor = start; + let count = usize::from(*data.get(cursor).ok_or(Error::IndexOutOfRange)?); + cursor += 1; + if count > MAX_EXTRA_PARAMS { + return Err(Error::Argument); + } + self.unknown_extra_params.clear(); + for _ in 0..count { + let header = data.get(cursor..cursor + 6).ok_or(Error::IndexOutOfRange)?; + let type_ = u16::from_le_bytes([header[0], header[1]]); + let length = usize::try_from(u32::from_le_bytes([ + header[2], header[3], header[4], header[5], + ])) + .map_err(|_| Error::Argument)?; + cursor += 6; + if length > MAX_EXTRA_PARAM_BYTES { + return Err(Error::Argument); + } + let payload = data + .get(cursor..cursor.checked_add(length).ok_or(Error::IndexOutOfRange)?) + .ok_or(Error::IndexOutOfRange)?; + match type_ { + 0x10 if length == 16 => { + self.flexible = Some(PrimitiveFlexibleData::new_with_bytes_int32( + payload.to_vec(), + 0, + )?); + } + 0x20 if length == 16 => { + self.light = Some(PrimitiveLightData::new_with_bytes_int32( + payload.to_vec(), + 0, + )?); + } + 0x40 if length == 28 => { + self.light_map = Some(PrimitiveLightImage::new_with_bytes_int32( + payload.to_vec(), + 0, + )?); + } + 0x30 | 0x60 if length == 17 => { + self.sculpt = Some(PrimitiveSculptData::new_with_bytes_int32( + payload.to_vec(), + 0, + )?); + } + 0x70 if length == 4 => { + self.extended_mesh_flags = + u32::from_le_bytes(payload.try_into().map_err(|_| Error::Argument)?); + } + _ => self.unknown_extra_params.push((type_, payload.to_vec())), + } + cursor += length; + } + i32::try_from(cursor - start).map_err(|_| Error::Argument) + } + + pub fn get_extra_params_bytes(&self) -> Result, Error> { + let mut params = Vec::<(u16, Vec)>::new(); + if let Some(value) = &self.flexible { + params.push((0x10, value.get_bytes()?)); + } + if let Some(value) = &self.light { + params.push((0x20, value.get_bytes()?)); + } + if let Some(value) = &self.light_map { + params.push((0x40, value.get_bytes()?)); + } + if let Some(value) = &self.sculpt { + params.push(( + if value.type_() == SculptType::Mesh { + 0x60 + } else { + 0x30 + }, + value.get_bytes()?, + )); + } + if self.extended_mesh_flags != 0 { + params.push((0x70, self.extended_mesh_flags.to_le_bytes().to_vec())); + } + params.extend(self.unknown_extra_params.clone()); + if params.len() > MAX_EXTRA_PARAMS { + return Err(Error::Argument); + } + let mut output = Vec::new(); + output.push(params.len() as u8); + for (type_, payload) in params { + if payload.len() > MAX_EXTRA_PARAM_BYTES { + return Err(Error::Argument); + } + output.extend_from_slice(&type_.to_le_bytes()); + output.extend_from_slice( + &u32::try_from(payload.len()) + .map_err(|_| Error::Argument)? + .to_le_bytes(), + ); + output.extend_from_slice(&payload); + } + Ok(output) + } + + pub fn get_hash_code(&self) -> i32 { + self.id.get_hash_code() + ^ self.prim_data.get_hash_code() + ^ self.local_id as i32 + ^ self.parent_id as i32 + } + pub fn to_string(&self) -> String { + if self.prim_data.p_code == PCode::Prim { + format!("{:?} ({})", self.type_(), self.id) + } else { + format!("{:?} ({})", self.prim_data.p_code, self.id) + } + } + pub fn pack_begin_cut(value: f32) -> Result { + Ok((value / 0.00002).round_ties_even() as u16) + } + pub fn pack_end_cut(value: f32) -> Result { + Ok(50_000_u16.wrapping_sub((value / 0.00002).round_ties_even() as u16)) + } + pub fn pack_path_scale(value: f32) -> Result { + Ok(200_u8.wrapping_sub((value / 0.01).round_ties_even() as u8)) + } + pub fn pack_path_shear(value: f32) -> Result { + Ok((value / 0.01).round_ties_even() as i8) + } + pub fn pack_path_twist(value: f32) -> Result { + Ok((value / 0.01).round_ties_even() as i8) + } + pub fn pack_path_taper(value: f32) -> Result { + Ok((value / 0.01).round_ties_even() as i8) + } + pub fn pack_path_revolutions(value: f32) -> Result { + Ok(((value - 1.0) / 0.015).round_ties_even() as u8) + } + pub fn pack_profile_hollow(value: f32) -> Result { + Ok((value / 0.00002).round_ties_even() as u16) + } + pub fn unpack_begin_cut(value: u16) -> Result { + Ok(f32::from(value) * 0.00002) + } + pub fn unpack_end_cut(value: u16) -> Result { + Ok(f32::from(50_000_u16.wrapping_sub(value)) * 0.00002) + } + pub fn unpack_path_scale(value: u8) -> Result { + Ok(f32::from(200_u8.wrapping_sub(value)) * 0.01) + } + pub fn unpack_path_shear(value: i8) -> Result { + Ok(f32::from(value) * 0.01) + } + pub fn unpack_path_twist(value: i8) -> Result { + Ok(f32::from(value) * 0.01) + } + pub fn unpack_path_taper(value: i8) -> Result { + Ok(f32::from(value) * 0.01) + } + pub fn unpack_path_revolutions(value: u8) -> Result { + Ok(f32::from(value).mul_add(0.015, 1.0)) + } + pub fn unpack_profile_hollow(value: u16) -> Result { + Ok(f32::from(value) * 0.00002) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct LegacyMaterial { + id: UUID, + normal_map: UUID, + normal_map_offset_x: f64, + normal_map_offset_y: f64, + normal_map_repeat_x: f64, + normal_map_repeat_y: f64, + normal_map_rotation: f64, + specular_map: UUID, + specular_map_offset_x: f64, + specular_map_offset_y: f64, + specular_map_repeat_x: f64, + specular_map_repeat_y: f64, + specular_map_rotation: f64, + specular_color: Color4, + specular_exponent: u8, + environment_intensity: u8, + alpha_mask_cutoff: u8, + diffuse_alpha_mode: crate::materials::LegacyMaterialAlphaMode, +} + +impl Default for LegacyMaterial { + fn default() -> Self { + Self { + id: UUID::zero(), + normal_map: UUID::zero(), + normal_map_offset_x: 0.0, + normal_map_offset_y: 0.0, + normal_map_repeat_x: 0.0, + normal_map_repeat_y: 0.0, + normal_map_rotation: 0.0, + specular_map: UUID::zero(), + specular_map_offset_x: 0.0, + specular_map_offset_y: 0.0, + specular_map_repeat_x: 0.0, + specular_map_repeat_y: 0.0, + specular_map_rotation: 0.0, + specular_color: Color4::black(), + specular_exponent: 0, + environment_intensity: 0, + alpha_mask_cutoff: 0, + diffuse_alpha_mode: crate::materials::LegacyMaterialAlphaMode::None, + } + } +} + +impl LegacyMaterial { + const MULTIPLIER: f64 = 10_000.0; + pub fn new_with_constructor() -> Result { + Ok(Self::default()) + } + pub fn new_with_osd_map(map_orig: OSDMap) -> Result { + let values = map_orig.snapshot(); + let id_value = values.get("ID").ok_or(Error::InvalidOperation)?; + let id = match id_value { + OSD::UUID(value) => *value, + OSD::Binary(_) | OSD::Array(_) => UUID::new_with_bytes_int32(id_value.as_binary()?, 0)?, + _ => return Err(Error::InvalidOperation), + }; + let Some(OSD::Map(material)) = values.get("Material") else { + return Err(Error::InvalidOperation); + }; + let scaled = |key: &str| -> f64 { + material + .get(key) + .and_then(|value| value.as_integer().ok()) + .map_or(0.0, |value| f64::from(value) / Self::MULTIPLIER) + }; + Ok(Self { + id, + normal_map: map_uuid(Some(material), "NormMap", UUID::zero()), + normal_map_offset_x: scaled("NormOffsetX"), + normal_map_offset_y: scaled("NormOffsetY"), + normal_map_repeat_x: scaled("NormRepeatX"), + normal_map_repeat_y: scaled("NormRepeatY"), + normal_map_rotation: scaled("NormRotation"), + specular_map: map_uuid(Some(material), "SpecMap", UUID::zero()), + specular_map_offset_x: scaled("SpecOffsetX"), + specular_map_offset_y: scaled("SpecOffsetY"), + specular_map_repeat_x: scaled("SpecRepeatX"), + specular_map_repeat_y: scaled("SpecRepeatY"), + specular_map_rotation: scaled("SpecRotation"), + specular_color: material + .get("SpecColor") + .and_then(|value| value.as_color4().ok()) + .unwrap_or_else(Color4::black), + specular_exponent: map_i32(Some(material), "SpecExp", 0) as u8, + environment_intensity: map_i32(Some(material), "EnvIntensity", 0) as u8, + alpha_mask_cutoff: map_i32(Some(material), "AlphaMaskCutoff", 0) as u8, + diffuse_alpha_mode: legacy_alpha_mode_from_i32(map_i32( + Some(material), + "DiffuseAlphaMode", + 0, + )), + }) + } + pub fn id(&self) -> UUID { + self.id + } + pub fn set_id(&mut self, value: UUID) { + self.id = value; + } + pub fn normal_map(&self) -> UUID { + self.normal_map + } + pub fn set_normal_map(&mut self, value: UUID) { + self.normal_map = value; + } + pub fn normal_map_offset_x(&self) -> f64 { + self.normal_map_offset_x + } + pub fn set_normal_map_offset_x(&mut self, value: f64) { + self.normal_map_offset_x = value; + } + pub fn normal_map_offset_y(&self) -> f64 { + self.normal_map_offset_y + } + pub fn set_normal_map_offset_y(&mut self, value: f64) { + self.normal_map_offset_y = value; + } + pub fn normal_map_repeat_x(&self) -> f64 { + self.normal_map_repeat_x + } + pub fn set_normal_map_repeat_x(&mut self, value: f64) { + self.normal_map_repeat_x = value; + } + pub fn normal_map_repeat_y(&self) -> f64 { + self.normal_map_repeat_y + } + pub fn set_normal_map_repeat_y(&mut self, value: f64) { + self.normal_map_repeat_y = value; + } + pub fn normal_map_rotation(&self) -> f64 { + self.normal_map_rotation + } + pub fn set_normal_map_rotation(&mut self, value: f64) { + self.normal_map_rotation = value; + } + pub fn specular_map(&self) -> UUID { + self.specular_map + } + pub fn set_specular_map(&mut self, value: UUID) { + self.specular_map = value; + } + pub fn specular_map_offset_x(&self) -> f64 { + self.specular_map_offset_x + } + pub fn set_specular_map_offset_x(&mut self, value: f64) { + self.specular_map_offset_x = value; + } + pub fn specular_map_offset_y(&self) -> f64 { + self.specular_map_offset_y + } + pub fn set_specular_map_offset_y(&mut self, value: f64) { + self.specular_map_offset_y = value; + } + pub fn specular_map_repeat_x(&self) -> f64 { + self.specular_map_repeat_x + } + pub fn set_specular_map_repeat_x(&mut self, value: f64) { + self.specular_map_repeat_x = value; + } + pub fn specular_map_repeat_y(&self) -> f64 { + self.specular_map_repeat_y + } + pub fn set_specular_map_repeat_y(&mut self, value: f64) { + self.specular_map_repeat_y = value; + } + pub fn specular_map_rotation(&self) -> f64 { + self.specular_map_rotation + } + pub fn set_specular_map_rotation(&mut self, value: f64) { + self.specular_map_rotation = value; + } + pub fn specular_color(&self) -> Color4 { + self.specular_color + } + pub fn set_specular_color(&mut self, value: Color4) { + self.specular_color = value; + } + pub fn specular_exponent(&self) -> u8 { + self.specular_exponent + } + pub fn set_specular_exponent(&mut self, value: u8) { + self.specular_exponent = value; + } + pub fn environment_intensity(&self) -> u8 { + self.environment_intensity + } + pub fn set_environment_intensity(&mut self, value: u8) { + self.environment_intensity = value; + } + pub fn alpha_mask_cutoff(&self) -> u8 { + self.alpha_mask_cutoff + } + pub fn set_alpha_mask_cutoff(&mut self, value: u8) { + self.alpha_mask_cutoff = value; + } + pub fn diffuse_alpha_mode(&self) -> crate::materials::LegacyMaterialAlphaMode { + self.diffuse_alpha_mode + } + pub fn set_diffuse_alpha_mode(&mut self, value: crate::materials::LegacyMaterialAlphaMode) { + self.diffuse_alpha_mode = value; + } +} + +const fn profile_curve_from_u8(value: u8) -> ProfileCurve { + match value { + 1 => ProfileCurve::Square, + 2 => ProfileCurve::IsoTriangle, + 3 => ProfileCurve::EqualTriangle, + 4 => ProfileCurve::RightTriangle, + 5 => ProfileCurve::HalfCircle, + _ => ProfileCurve::Circle, + } +} +const fn material_from_i32(value: i32) -> Material { + match value { + 1 => Material::Metal, + 2 => Material::Glass, + 3 => Material::Wood, + 4 => Material::Flesh, + 5 => Material::Plastic, + 6 => Material::Rubber, + 7 => Material::Light, + _ => Material::Stone, + } +} +const fn pcode_from_i32(value: i32) -> PCode { + match value { + 9 => PCode::Prim, + 47 => PCode::Avatar, + 95 => PCode::Grass, + 111 => PCode::NewTree, + 143 => PCode::ParticleSystem, + 255 => PCode::Tree, + _ => PCode::None, + } +} +const fn path_curve_from_i32(value: i32) -> PathCurve { + match value { + 32 => PathCurve::Circle, + 48 => PathCurve::Circle2, + 64 => PathCurve::Test, + 128 => PathCurve::Flexible, + _ => PathCurve::Line, + } +} +const fn sculpt_type_from_u8(value: u8) -> SculptType { + match value { + 1 => SculptType::Sphere, + 2 => SculptType::Torus, + 3 => SculptType::Plane, + 4 => SculptType::Cylinder, + 5 => SculptType::Mesh, + _ => SculptType::None, + } +} +const fn mapping_type_from_u8(value: u8) -> MappingType { + match value { + 2 => MappingType::Planar, + 4 => MappingType::Spherical, + 6 => MappingType::Cylindrical, + _ => MappingType::Default, + } +} +const fn shininess_from_u8(value: u8) -> Shininess { + match value { + 0x40 => Shininess::Low, + 0x80 => Shininess::Medium, + 0xc0 => Shininess::High, + _ => Shininess::None, + } +} +const fn bumpiness_from_u8(value: u8) -> Bumpiness { + match value { + 1 => Bumpiness::Brightness, + 2 => Bumpiness::Darkness, + 3 => Bumpiness::Woodgrain, + 4 => Bumpiness::Bark, + 5 => Bumpiness::Bricks, + 6 => Bumpiness::Checker, + 7 => Bumpiness::Concrete, + 8 => Bumpiness::Crustytile, + 9 => Bumpiness::Cutstone, + 10 => Bumpiness::Discs, + 11 => Bumpiness::Gravel, + 12 => Bumpiness::Petridish, + 13 => Bumpiness::Siding, + 14 => Bumpiness::Stonetile, + 15 => Bumpiness::Stucco, + 16 => Bumpiness::Suction, + 17 => Bumpiness::Weave, + _ => Bumpiness::None, + } +} +const fn grass_from_u8(value: u8) -> Grass { + match value { + 1 => Grass::Grass1, + 2 => Grass::Grass2, + 3 => Grass::Grass3, + 4 => Grass::Grass4, + 5 => Grass::Undergrowth1, + _ => Grass::Grass0, + } +} +const fn legacy_alpha_mode_from_i32(value: i32) -> crate::materials::LegacyMaterialAlphaMode { + match value { + 1 => crate::materials::LegacyMaterialAlphaMode::Blend, + 2 => crate::materials::LegacyMaterialAlphaMode::Mask, + 3 => crate::materials::LegacyMaterialAlphaMode::Emissive, + 4 => crate::materials::LegacyMaterialAlphaMode::Default, + _ => crate::materials::LegacyMaterialAlphaMode::None, + } +} +const fn attachment_point_from_u8(value: u8) -> AttachmentPoint { + match value { + 1 => AttachmentPoint::Chest, + 2 => AttachmentPoint::Skull, + 3 => AttachmentPoint::LeftShoulder, + 4 => AttachmentPoint::RightShoulder, + 5 => AttachmentPoint::LeftHand, + 6 => AttachmentPoint::RightHand, + 7 => AttachmentPoint::LeftFoot, + 8 => AttachmentPoint::RightFoot, + 9 => AttachmentPoint::Spine, + 10 => AttachmentPoint::Pelvis, + 11 => AttachmentPoint::Mouth, + 12 => AttachmentPoint::Chin, + 13 => AttachmentPoint::LeftEar, + 14 => AttachmentPoint::RightEar, + 15 => AttachmentPoint::LeftEyeball, + 16 => AttachmentPoint::RightEyeball, + 17 => AttachmentPoint::Nose, + 18 => AttachmentPoint::RightUpperArm, + 19 => AttachmentPoint::RightForearm, + 20 => AttachmentPoint::LeftUpperArm, + 21 => AttachmentPoint::LeftForearm, + 22 => AttachmentPoint::RightHip, + 23 => AttachmentPoint::RightUpperLeg, + 24 => AttachmentPoint::RightLowerLeg, + 25 => AttachmentPoint::LeftHip, + 26 => AttachmentPoint::LeftUpperLeg, + 27 => AttachmentPoint::LeftLowerLeg, + 28 => AttachmentPoint::Stomach, + 29 => AttachmentPoint::LeftPec, + 30 => AttachmentPoint::RightPec, + 31 => AttachmentPoint::HUDCenter2, + 32 => AttachmentPoint::HUDTopRight, + 33 => AttachmentPoint::HUDTop, + 34 => AttachmentPoint::HUDTopLeft, + 35 => AttachmentPoint::HUDCenter, + 36 => AttachmentPoint::HUDBottomLeft, + 37 => AttachmentPoint::HUDBottom, + 38 => AttachmentPoint::HUDBottomRight, + 39 => AttachmentPoint::Neck, + 40 => AttachmentPoint::Root, + 41 => AttachmentPoint::LeftHandRing, + 42 => AttachmentPoint::RightHandRing, + 43 => AttachmentPoint::TailBase, + 44 => AttachmentPoint::TailTip, + 45 => AttachmentPoint::LeftWing, + 46 => AttachmentPoint::RightWing, + 47 => AttachmentPoint::Jaw, + 48 => AttachmentPoint::AltLeftEar, + 49 => AttachmentPoint::AltRightEar, + 50 => AttachmentPoint::AltLeftEye, + 51 => AttachmentPoint::AltRightEye, + 52 => AttachmentPoint::Tongue, + 53 => AttachmentPoint::Groin, + 54 => AttachmentPoint::LeftHindFoot, + 55 => AttachmentPoint::RightHindFoot, + _ => AttachmentPoint::Default, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn texture_faces_inherit_live_defaults_and_clone_independently() { + let mut entry = PrimitiveTextureEntry::new_with_uuid(UUID::zero()).unwrap(); + entry.create_face(7).unwrap(); + entry.default_texture.as_mut().unwrap().set_repeat_u(2.5); + assert_eq!(entry.face_textures[7].as_ref().unwrap().repeat_u(), 2.5); + + entry.face_textures[7].as_mut().unwrap().set_repeat_u(4.0); + entry.default_texture.as_mut().unwrap().set_repeat_u(3.0); + assert_eq!(entry.face_textures[7].as_ref().unwrap().repeat_u(), 4.0); + + let copy = PrimitiveTextureEntry::new_with_texture_entry(entry.clone()).unwrap(); + entry.default_texture.as_mut().unwrap().set_repeat_v(8.0); + assert_eq!(copy.default_texture.as_ref().unwrap().repeat_v(), 1.0); + } + + #[test] + fn texture_entry_rejects_unterminated_face_bitfields() { + let mut malformed = vec![0_u8; 16]; + malformed.extend_from_slice(&[0x80; 10]); + assert!(matches!( + PrimitiveTextureEntry::new_with_bytes_int32_int32( + malformed.clone(), + 0, + malformed.len() as i32 + ), + Err(Error::Argument) + )); + } + + #[test] + fn particle_system_legacy_and_extended_bytes_are_stable() { + let mut legacy = PrimitiveParticleSystem::default(); + legacy.crc = 0x1234_5678; + legacy.part_flags = 0x8000_0001; + legacy.pattern = PrimitiveParticleSystemSourcePattern::ANGLE_CONE; + legacy.max_age = 12.5; + legacy.burst_part_count = 17; + legacy.part_data_flags = PrimitiveParticleSystemParticleDataFlags( + PrimitiveParticleSystemParticleDataFlags::INTERP_COLOR.0 | 0x8000_0000, + ); + legacy.part_start_color = Color4::white(); + legacy.part_end_color = Color4::black(); + legacy.part_start_scale_x = 1.0; + legacy.part_start_scale_y = 2.0; + let bytes = legacy.get_bytes().unwrap(); + assert_eq!( + bytes.len(), + usize::from(PrimitiveParticleSystem::LEGACY_DATA_BLOCK_SIZE) + ); + let decoded = PrimitiveParticleSystem::new(bytes.clone(), 0).unwrap(); + assert_eq!(decoded.get_bytes().unwrap(), bytes); + assert_ne!(decoded.part_data_flags.0 & 0x8000_0000, 0); + + let mut extended = legacy; + extended.part_start_glow = 0.5; + extended.part_end_glow = 1.0; + extended.blend_func_source = PrimitiveParticleSystemBlendFunc::One as u8; + extended.blend_func_dest = PrimitiveParticleSystemBlendFunc::Zero as u8; + let bytes = extended.get_bytes().unwrap(); + assert_eq!( + bytes.len(), + usize::from(PrimitiveParticleSystem::MAX_DATA_BLOCK_SIZE) + ); + let decoded = PrimitiveParticleSystem::new(bytes.clone(), 0).unwrap(); + assert_eq!(decoded.get_bytes().unwrap(), bytes); + assert!(decoded.has_glow().unwrap()); + assert!(decoded.has_blend_func().unwrap()); + assert_ne!( + decoded.part_data_flags.0 & PrimitiveParticleSystemParticleDataFlags::DATA_GLOW.0, + 0 + ); + assert_ne!( + decoded.part_data_flags.0 & PrimitiveParticleSystemParticleDataFlags::DATA_BLEND.0, + 0 + ); + } + + #[test] + fn particle_and_extra_parameter_decoders_are_bounded() { + assert!(matches!( + PrimitiveParticleSystem::new( + vec![0; usize::from(PrimitiveParticleSystem::MAX_DATA_BLOCK_SIZE) + 1], + 0 + ), + Err(Error::Argument) + )); + assert!(PrimitiveParticleSystem::new(vec![0; 85], 0).is_err()); + + let unknown = vec![1, 0x99, 0x99, 3, 0, 0, 0, 1, 2, 3]; + let mut primitive = Primitive::new_with_constructor().unwrap(); + assert_eq!( + primitive + .set_extra_params_from_bytes(unknown.clone(), 0) + .unwrap(), + unknown.len() as i32 + ); + assert_eq!(primitive.get_extra_params_bytes().unwrap(), unknown); + + let oversized = (MAX_EXTRA_PARAM_BYTES as u32 + 1).to_le_bytes(); + let malformed = vec![ + 1, + 0x99, + 0x99, + oversized[0], + oversized[1], + oversized[2], + oversized[3], + ]; + assert!(matches!( + primitive.set_extra_params_from_bytes(malformed, 0), + Err(Error::Argument) + )); + } + + #[test] + fn auxiliary_primitive_blobs_round_trip_without_losing_type_bits() { + let mut flexible = PrimitiveFlexibleData::default(); + flexible.softness = 3; + flexible.tension = 1.5; + flexible.drag = 0.7; + flexible.gravity = -4.0; + flexible.wind = 0.2; + flexible.force = Vector3 { + x: 1.0, + y: -2.0, + z: 3.0, + }; + let flexible_bytes = flexible.get_bytes().unwrap(); + assert_eq!( + PrimitiveFlexibleData::new_with_bytes_int32(flexible_bytes.clone(), 0) + .unwrap() + .get_bytes() + .unwrap(), + flexible_bytes + ); + + let mut light = PrimitiveLightData::default(); + light.color = Color4 { + r: 0.2, + g: 0.4, + b: 0.6, + a: 1.0, + }; + light.intensity = 0.8; + light.radius = 12.0; + light.cutoff = 0.5; + light.falloff = 1.25; + let light_bytes = light.get_bytes().unwrap(); + assert_eq!( + PrimitiveLightData::new_with_bytes_int32(light_bytes.clone(), 0) + .unwrap() + .get_bytes() + .unwrap(), + light_bytes + ); + + let sculpt_bytes = { + let mut bytes = UUID::zero().get_bytes().unwrap(); + bytes + .push(SculptType::Mesh as u8 | SculptType::Invert as u8 | SculptType::Mirror as u8); + bytes + }; + let sculpt = PrimitiveSculptData::new_with_bytes_int32(sculpt_bytes.clone(), 0).unwrap(); + assert_eq!(sculpt.type_(), SculptType::Mesh); + assert!(sculpt.invert()); + assert!(sculpt.mirror()); + assert_eq!(sculpt.get_bytes().unwrap(), sculpt_bytes); + } + + #[test] + fn legacy_material_and_media_osd_preserve_wire_values() { + let id = UUID::random().unwrap(); + let normal = UUID::random().unwrap(); + let material = HashMap::from([ + ("NormMap".into(), OSD::UUID(normal)), + ("NormOffsetX".into(), OSD::Integer(1250)), + ("SpecExp".into(), OSD::Integer(42)), + ("DiffuseAlphaMode".into(), OSD::Integer(2)), + ]); + let legacy = LegacyMaterial::new_with_osd_map( + OSDMap::new_with_dictionary(HashMap::from([ + ("ID".into(), OSD::UUID(id)), + ("Material".into(), OSD::Map(material)), + ])) + .unwrap(), + ) + .unwrap(); + assert_eq!(legacy.id(), id); + assert_eq!(legacy.normal_map(), normal); + assert_eq!(legacy.normal_map_offset_x(), 0.125); + assert_eq!(legacy.specular_exponent(), 42); + assert_eq!( + legacy.diffuse_alpha_mode(), + crate::materials::LegacyMaterialAlphaMode::Mask + ); + + let mut media = MediaEntry::new().unwrap(); + media.auto_loop = true; + media.current_url = "https://example.invalid/current".into(); + media.home_url = "https://example.invalid/home".into(); + media.white_list = vec!["https://example.invalid/*".into()]; + media.enable_white_list = true; + media.width = 1024; + media.height = 768; + let decoded = MediaEntry::from_osd(OSD::Map(media.get_osd().unwrap().snapshot())).unwrap(); + assert_eq!(decoded, media); + assert!(MediaEntry::from_osd(OSD::Undefined).unwrap().is_undefined()); + } +} diff --git a/crates/libremetaverse/src/visual_catalog.rs b/crates/libremetaverse/src/visual_catalog.rs index a4f2731..35c366c 100644 --- a/crates/libremetaverse/src/visual_catalog.rs +++ b/crates/libremetaverse/src/visual_catalog.rs @@ -23352,12 +23352,6 @@ pub(crate) fn new_avatar() -> Result { visual_parameters: Vec::new(), }) } -pub(crate) fn new_texture_entry_face() -> Result< - crate::PrimitiveTextureEntryFace, - crate::Error, -> { - Ok(crate::PrimitiveTextureEntryFace) -} #[cfg(test)] mod tests { use super::*; diff --git a/tests/compat/tests/wire_shims.rs b/tests/compat/tests/wire_shims.rs index 5ab0a87..4da1fe7 100644 --- a/tests/compat/tests/wire_shims.rs +++ b/tests/compat/tests/wire_shims.rs @@ -29,14 +29,6 @@ fn each_wire_data_domain_is_callable_and_failure_only() { member_id(AssetTexture::new_with_constructor()), "M:LibreMetaverse.Assets.AssetTexture.#ctor" ); - assert_eq!( - member_id(Primitive::new_with_constructor()), - "M:LibreMetaverse.Primitive.#ctor" - ); - assert_eq!( - member_id(LegacyMaterial::new_with_constructor()), - "M:LibreMetaverse.Materials.LegacyMaterial.#ctor" - ); assert_eq!( member_id(GltfDocument::new()), "M:LibreMetaverse.Assets.Gltf.GltfDocument.#ctor" @@ -58,6 +50,22 @@ fn each_wire_data_domain_is_callable_and_failure_only() { ); } +#[test] +fn object_model_domains_are_native() { + assert_eq!( + Primitive::new_with_constructor() + .expect("native primitive constructor") + .local_id, + 0 + ); + assert_eq!( + LegacyMaterial::new_with_constructor() + .expect("native legacy material constructor") + .id(), + libremetaverse_types::UUID::zero() + ); +} + #[test] fn wire_widths_flags_and_constants_match_the_catalog() { assert_eq!(PacketFrequency::High as u8, 2); diff --git a/tools/codegen/src/xml_catalog.rs b/tools/codegen/src/xml_catalog.rs index c1bcd3b..e613134 100644 --- a/tools/codegen/src/xml_catalog.rs +++ b/tools/codegen/src/xml_catalog.rs @@ -890,7 +890,6 @@ fn render_visual_catalog(catalog: &VisualCatalog) -> String { visual_parameters: Vec::new(),\n\ })\n\ }\n\n\ - pub(crate) fn new_texture_entry_face() -> Result { Ok(crate::PrimitiveTextureEntryFace) }\n\n\ #[cfg(test)] mod tests { use super::*; #[test] fn golden_catalog_shape_and_values() { let params = generated_params(); assert_eq!(params.len(), 672); assert_eq!(GROUP0_PARAM_IDS.len(), 253); assert!(GROUP0_PARAM_IDS.windows(2).all(|ids| ids[0] < ids[1])); let height = ¶ms[&33]; assert_eq!(height.name, \"Height\"); assert_eq!(height.group, 0); assert_eq!(height.wearable.as_deref(), Some(\"shape\")); assert_eq!(height.min_value, -2.3); assert_eq!(height.max_value, 2.0); assert!(!height.skeletal_distortions.as_ref().unwrap().is_empty()); } }\n", ); body diff --git a/tools/generate_api_shims.py b/tools/generate_api_shims.py index 2b6ca0d..deadfa1 100644 --- a/tools/generate_api_shims.py +++ b/tools/generate_api_shims.py @@ -197,6 +197,18 @@ NATIVE_TYPES = { "T:LibreMetaverse.Messages.Linden.EventQueueGetMessage": "crate::event_queue::EventQueueGetMessage", "T:LibreMetaverse.Messages.Linden.AttachmentResourcesMessage": "crate::message_decoder::AttachmentResourcesMessage", "T:LibreMetaverse.Primitive.PhysicsProperties": "crate::message_decoder::PrimitivePhysicsProperties", + "T:LibreMetaverse.Primitive": "crate::object_model::Primitive", + "T:LibreMetaverse.Primitive.ConstructionData": "crate::object_model::PrimitiveConstructionData", + "T:LibreMetaverse.Primitive.FlexibleData": "crate::object_model::PrimitiveFlexibleData", + "T:LibreMetaverse.Primitive.LightData": "crate::object_model::PrimitiveLightData", + "T:LibreMetaverse.Primitive.LightImage": "crate::object_model::PrimitiveLightImage", + "T:LibreMetaverse.Primitive.ObjectProperties": "crate::object_model::PrimitiveObjectProperties", + "T:LibreMetaverse.Primitive.ParticleSystem": "crate::object_model::PrimitiveParticleSystem", + "T:LibreMetaverse.Primitive.SculptData": "crate::object_model::PrimitiveSculptData", + "T:LibreMetaverse.Primitive.TextureAnimation": "crate::object_model::PrimitiveTextureAnimation", + "T:LibreMetaverse.Primitive.TextureEntry": "crate::object_model::PrimitiveTextureEntry", + "T:LibreMetaverse.Primitive.TextureEntryFace": "crate::object_model::PrimitiveTextureEntryFace", + "T:LibreMetaverse.Materials.LegacyMaterial": "crate::object_model::LegacyMaterial", "T:LibreMetaverse.ArchetypeParam": "crate::genepool_catalog::ArchetypeParam", "T:LibreMetaverse.AttentionData": "crate::attention_catalog::AttentionData", "T:LibreMetaverse.AttentionSet": "crate::attention_catalog::AttentionSet", @@ -330,6 +342,18 @@ NATIVE_DECLARATIONS = { } NATIVE_MEMBER_BODIES = { + "M:LibreMetaverse.Helpers.TEGlowByte(System.Single)": + "Ok(crate::object_model::te_glow_byte(glow))", + "M:LibreMetaverse.Helpers.TEGlowFloat(System.Byte[],System.Int32)": + "crate::object_model::te_glow_float(bytes, pos)", + "M:LibreMetaverse.Helpers.TEOffsetFloat(System.Byte[],System.Int32)": + "crate::object_model::te_offset_float(bytes, pos)", + "M:LibreMetaverse.Helpers.TEOffsetShort(System.Single)": + "Ok(crate::object_model::te_offset_short(offset))", + "M:LibreMetaverse.Helpers.TERotationFloat(System.Byte[],System.Int32)": + "crate::object_model::te_rotation_float(bytes, pos)", + "M:LibreMetaverse.Helpers.TERotationShort(System.Single)": + "Ok(crate::object_model::te_rotation_short(rotation))", "M:LibreMetaverse.AvatarAnimationEventArgs.#ctor(LibreMetaverse.UUID,System.Collections.Generic.List{LibreMetaverse.Animation})": "crate::avatar_manager::AvatarAnimationEventArgs::native_new(avatar_id, anims)", "P:LibreMetaverse.AvatarAnimationEventArgs.Animations": @@ -1871,8 +1895,6 @@ NATIVE_MEMBER_BODIES = { "crate::foliage_catalog::grass_by_id(self.prim_data.state)", "M:LibreMetaverse.Primitive.GetTreeDefinition": "crate::foliage_catalog::TreeDefinitions::get(self.tree_species)", - "M:LibreMetaverse.Primitive.TextureEntryFace.#ctor(LibreMetaverse.Primitive.TextureEntryFace)": - "crate::visual_catalog::new_texture_entry_face()", "M:LibreMetaverse.StructuredData.OSDParser.BufferCharactersEqual(System.IO.StringReader,System.Char[],System.Int32)": "crate::notation::buffer_characters_equal(reader, buffer, offset)", "M:LibreMetaverse.StructuredData.OSDParser.ConsumeBytes(System.IO.Stream,System.Int32)": diff --git a/tools/generate_rust_mapping.py b/tools/generate_rust_mapping.py index 92f6c06..f481efa 100644 --- a/tools/generate_rust_mapping.py +++ b/tools/generate_rust_mapping.py @@ -1014,6 +1014,7 @@ def validate_generated_shims() -> None: "crate::message_decoder::", "crate::NameValue {", "crate::object_material::", + "crate::object_model::", "crate::notation::", "crate::packet_catalog::", "crate::packet_wire::",