//! Native Rust grid client corresponding to the main `LibreMetaverse` assembly. //! //! Start here for login, networking, agents, inventory, assets, appearance, //! world, and social APIs. The appended guide covers crate selection, C# name //! migration, ownership, cancellation, events, security, and `OpenSim` setup. #![doc = include_str!("../README.md")] extern crate self as libremetaverse; #[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator. mod attention_catalog; mod agent_manager; mod agent_messages; mod agent_movement; mod animation; #[path = "animesh.rs"] mod animesh_runtime; mod animesh_skinning; mod appearance_baker; mod appearance_manager; mod asset_archive; mod asset_cache; mod asset_manager; mod asset_material; mod asset_models; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod asset_prim; mod avatar_manager; mod avatar_rig; mod baking_texture_provider; mod bit_pack; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod builtin_simple_renderer; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod callback_runtime; mod caps; mod caps_http; mod client_core; mod current_outfit; mod download_manager; mod environment_manager; mod estate_tools; mod event_queue; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod event_subscription; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod file_helper; mod friends_manager; mod gesture; mod gltf; mod group_manager; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod helpers; mod initial_outfit; mod inventory; mod inventory_ais; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod inventory_exception; mod inventory_manager; #[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator. mod foliage_catalog; mod generated; #[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator. mod genepool_catalog; mod j2k; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod linden_mesh; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod logger; mod login; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod lsl_syntax; #[path = "marketplace.rs"] mod marketplace_runtime; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod mesh_asset; mod message_codec; mod message_decoder; mod model_workflow; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod name_value; mod network_manager; mod object_manager; mod object_material; mod object_model; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod observable_dictionary; #[rustfmt::skip] pub mod packet_catalog; mod directory_manager; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod disposal_helper; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod dynamic_messages; mod grid_manager; pub use grid_manager::MapItemData; mod interest_list; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod packet_base; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod packet_decoder; mod packet_wire; mod parcel_manager; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod particle_simulator; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod port_errors; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod position_helper; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod prim_object; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod protocol_manager; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod rendering_binary_reader; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod rendering_loader; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod rendering_metadata; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod repeat; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod service_collection; mod sim_stats; mod skeleton; mod slurl; mod sound_manager; #[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator. mod skeleton_catalog; mod targa; mod terrain_codec; mod terrain_manager; mod transfers; mod udp_transport; mod user_report; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod uuid_formatter; #[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator. mod visual_catalog; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod avatar_model; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod avatar_physics; #[cfg(test)] mod appearance_baker_semantics; #[cfg(test)] mod asset_archive_semantics; #[cfg(test)] mod asset_pipeline_semantics; #[cfg(test)] mod avatar_animesh_semantics; #[cfg(test)] mod batch_link_internal_semantics; #[cfg(test)] mod inventory_ais_internal_semantics; #[cfg(test)] mod world_internal_semantics; type Terrain = Vec>; type TerrainLoaded = Box; impl assets::OarFile { #[allow(dead_code, clippy::needless_pass_by_value)] fn load_terrain( file_path: &str, data: Vec, callback: TerrainLoaded, bytes_read: i64, total_bytes: i64, ) -> Result { crate::asset_archive::load_terrain(file_path, &data, callback, bytes_read, total_bytes) } } #[allow(dead_code)] impl animesh::AnimationTrack { fn new(animation_id: libremetaverse_types::UUID) -> Result { Self::native_new(animation_id) } fn decode_rotation( value: libremetaverse_types::Vector3, ) -> Result { Self::native_decode_rotation(value) } } #[allow( clippy::needless_pass_by_value, clippy::unnecessary_wraps, clippy::unused_self, dead_code )] impl animesh::AnimeshPlayer { fn new(object_id: libremetaverse_types::UUID) -> Result { Self::native_new(object_id) } fn get_or_add_track( &mut self, animation_id: libremetaverse_types::UUID, ) -> Result, Error> { self.native_get_or_add_track(animation_id) } fn retain_only( &mut self, animation_ids: std::collections::HashSet, ) -> Result<(), Error> { self.native_retain_only(&animation_ids); Ok(()) } } #[allow(dead_code)] // Internal C# surface consumed by InventoryManager workflows. impl InventoryAISClient { async fn create_inventory_links( &self, parent_uuid: libremetaverse_types::UUID, new_inventory: libremetaverse_structured_data::OSD, cancellation_token: Option, ) -> Result, Error> { self.native_create_inventory_links(parent_uuid, new_inventory, cancellation_token) .await } } #[allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)] impl NetworkManager { fn raise_sim_console_response( &self, message: messages::linden::SimConsoleResponseMessage, simulator: Simulator, ) -> Result<(), Error> { self.dispatch_caps_event("SimConsoleResponse", &message, simulator); Ok(()) } } #[allow(dead_code)] impl imaging::Baker { fn resize_to_bake_dimensions( source: libremetaverse_imaging::ManagedImage, width: i32, height: i32, ) -> Result, Error> { crate::appearance_baker::Baker::native_resize_to_bake_dimensions(source, width, height) } } pub use callback_runtime::{AsyncInvocation, DictionaryCallbackTarget}; pub use caps_http::CapsHttpLimits; pub use client_core::{ ClientCoreError, ClientLifecycleState, ClientService, GridClientBuilder, ShutdownPhase, }; pub use generated::*; pub use libremetaverse_imaging as imaging_abstractions; pub use libremetaverse_structured_data as structured_data; pub use libremetaverse_types as types; pub use libremetaverse_types::Error; pub use logger::LoggerCallbackTarget; pub use network_manager::SimulatorCollection; pub use udp_transport::{ AgentThrottleSender, UdpPacketHandler, UdpThrottleCategory, UdpTransportConfig, UdpTransportError, UdpTransportStats, }; pub use user_report::{UserReport, UserReportService, UserReportType}; pub(crate) fn is_offline_fixture_uri(uri: &libremetaverse_types::compat::Uri) -> bool { reqwest::Url::parse(&uri.0) .ok() .and_then(|url| url.host_str().map(str::to_owned)) .is_some_and(|host| host == "invalid" || host.ends_with(".invalid")) } #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod collada; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod coordinate_frame; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod physics_volume_morphs; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod simulator_data_pool; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod sound_catalog; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod statistics_runtime; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod texture_pipeline; #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the pinned C# API. mod threading_runtime; /// Rust object-safe view of the C# `InventoryBase` inheritance hierarchy. pub trait InventoryObjectClass: std::any::Any { /// Returns the concrete value for exact C# runtime-type checks. fn as_any(&self) -> &dyn std::any::Any; /// Returns the shared `InventoryBase` portion of the concrete object. fn inventory_base(&self) -> &InventoryBase; /// Returns the shared `InventoryItem` portion for item-derived objects. fn inventory_item(&self) -> Option<&InventoryItem> { None } } /// Rust object-safe view of concrete classes derived from C# `InventoryItem`. pub trait InventoryItemClass: InventoryObjectClass {} macro_rules! inventory_object_class { ($type:ty, $base:ident $(.$nested:ident)*) => { impl InventoryObjectClass for $type { fn as_any(&self) -> &dyn std::any::Any { self } fn inventory_base(&self) -> &InventoryBase { &self.$base$(.$nested)* } } }; } macro_rules! inventory_item_class { ($type:ty, $item:ident $(.$nested:ident)*) => { impl InventoryObjectClass for $type { fn as_any(&self) -> &dyn std::any::Any { self } fn inventory_base(&self) -> &InventoryBase { &self.$item$(.$nested)*.base } fn inventory_item(&self) -> Option<&InventoryItem> { Some(&self.$item$(.$nested)*) } } }; } impl InventoryObjectClass for InventoryBase { fn as_any(&self) -> &dyn std::any::Any { self } fn inventory_base(&self) -> &InventoryBase { self } } inventory_object_class!(InventoryFolder, base); impl InventoryObjectClass for InventoryItem { fn as_any(&self) -> &dyn std::any::Any { self } fn inventory_base(&self) -> &InventoryBase { &self.base } fn inventory_item(&self) -> Option<&InventoryItem> { Some(self) } } inventory_item_class!(InventoryAnimation, base); inventory_item_class!(InventoryAttachment, base); inventory_item_class!(InventoryCallingCard, base); inventory_item_class!(InventoryCategory, base); inventory_item_class!(InventoryGesture, base); inventory_item_class!(InventoryLSL, base); inventory_item_class!(InventoryLandmark, base); inventory_item_class!(InventoryMaterial, base); inventory_item_class!(InventoryNotecard, base); inventory_item_class!(InventoryObject, base); inventory_item_class!(InventorySettings, base); inventory_item_class!(InventorySnapshot, base); inventory_item_class!(InventorySound, base); inventory_item_class!(InventoryTexture, base); inventory_item_class!(InventoryWearable, base); impl InventoryItemClass for InventoryItem {} impl InventoryItemClass for InventoryAnimation {} impl InventoryItemClass for InventoryAttachment {} impl InventoryItemClass for InventoryCallingCard {} impl InventoryItemClass for InventoryCategory {} impl InventoryItemClass for InventoryGesture {} impl InventoryItemClass for InventoryLSL {} impl InventoryItemClass for InventoryLandmark {} impl InventoryItemClass for InventoryMaterial {} impl InventoryItemClass for InventoryNotecard {} impl InventoryItemClass for InventoryObject {} impl InventoryItemClass for InventorySettings {} impl InventoryItemClass for InventorySnapshot {} impl InventoryItemClass for InventorySound {} impl InventoryItemClass for InventoryTexture {} impl InventoryItemClass for InventoryWearable {} /// Project-owned boundary types for external `MessagePack` signatures. #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the external API boundary. pub mod message_pack { use libremetaverse_types::Error; pub trait IMessagePackFormatter { fn serialize( &self, writer: &mut MessagePackWriter, value: T, options: MessagePackSerializerOptions, ) -> Result<(), Error>; fn deserialize( &mut self, reader: &mut MessagePackReader, options: MessagePackSerializerOptions, ) -> Result; } #[derive(Clone, Debug)] pub struct MessagePackReader { bytes: Vec, position: usize, } impl MessagePackReader { #[must_use] pub fn new(bytes: Vec) -> Self { Self { bytes, position: 0 } } pub fn read_bytes(&mut self) -> Result>, Error> { let marker = *self .bytes .get(self.position) .ok_or(Error::IndexOutOfRange)?; self.position += 1; if marker == 0xc0 { return Ok(None); } let length = match marker { 0xc4 => { let length = *self .bytes .get(self.position) .ok_or(Error::IndexOutOfRange)?; self.position += 1; usize::from(length) } 0xc5 => { let length = self .bytes .get(self.position..self.position + 2) .ok_or(Error::IndexOutOfRange)?; self.position += 2; usize::from(u16::from_be_bytes([length[0], length[1]])) } 0xc6 => { let length = self .bytes .get(self.position..self.position + 4) .ok_or(Error::IndexOutOfRange)?; self.position += 4; usize::try_from(u32::from_be_bytes([ length[0], length[1], length[2], length[3], ])) .map_err(|_| Error::IndexOutOfRange)? } _ => { return Err(Error::Parse { position: self.position - 1, context: "MessagePack binary marker", }); } }; let end = self .position .checked_add(length) .ok_or(Error::IndexOutOfRange)?; let value = self .bytes .get(self.position..end) .ok_or(Error::IndexOutOfRange)? .to_vec(); self.position = end; Ok(Some(value)) } } #[derive(Clone, Copy, Debug, Default)] pub struct MessagePackSerializerOptions; #[derive(Clone, Debug, Default)] pub struct MessagePackWriter { bytes: Vec, } impl MessagePackWriter { #[must_use] pub fn new() -> Self { Self::default() } pub fn write_bytes(&mut self, value: &[u8]) -> Result<(), Error> { match value.len() { length if u8::try_from(length).is_ok() => { self.bytes.push(0xc4); self.bytes.push(length as u8); } length if u16::try_from(length).is_ok() => { self.bytes.push(0xc5); self.bytes.extend_from_slice(&(length as u16).to_be_bytes()); } length => { self.bytes.push(0xc6); let length = u32::try_from(length).map_err(|_| Error::Argument)?; self.bytes.extend_from_slice(&length.to_be_bytes()); } } self.bytes.extend_from_slice(value); Ok(()) } #[must_use] pub fn as_slice(&self) -> &[u8] { &self.bytes } #[must_use] pub fn into_bytes(self) -> Vec { self.bytes } } } /// Project-owned boundary types for external logging signatures. #[allow(clippy::all, clippy::pedantic)] // Public shapes mirror the external API boundary. pub mod logging { use std::sync::Arc; use libremetaverse_types::compat::{Close, ExternalError, Object}; pub trait ILogger: Send + Sync { fn is_enabled(&self, level: LogLevel) -> bool; fn log( &self, level: LogLevel, message: &Object, exception: Option<&ExternalError>, client_name: Option<&str>, ); fn begin_scope(&self, state: Object) -> Box; } pub trait ILoggerFactory: Send + Sync { fn create_logger(&self, name: &str) -> Arc; fn shutdown(&self) -> Result<(), ExternalError>; } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct LogLevel(pub i32); impl LogLevel { pub const TRACE: Self = Self(0); pub const DEBUG: Self = Self(1); pub const INFORMATION: Self = Self(2); pub const WARNING: Self = Self(3); pub const ERROR: Self = Self(4); pub const CRITICAL: Self = Self(5); pub const NONE: Self = Self(6); } } /// Project-owned boundary types for external networking signatures. pub mod net { pub struct RateLimiter; pub struct Socket; pub struct TcpStream; pub struct UdpSocket; } /// Project-owned boundary types for external service-collection signatures. pub mod services { pub use crate::service_collection::{IServiceCollection, ServiceCollection}; } /// Common behavior for program shims while the network stack is unimplemented. pub mod shim { use std::process::ExitCode; /// Reports that an upstream sample has a target but no implementation yet. #[must_use] pub fn pending_program(name: &str) -> ExitCode { eprintln!("{name}: LibreMetaverse Rust port is not implemented yet"); ExitCode::FAILURE } }