Implement appearance and current outfit services (#65)
This commit is contained in:
10
README.md
10
README.md
@@ -382,3 +382,13 @@ side-effect removals, and folder versions are validated and reconciled through
|
|||||||
one atomic store transaction; cancellation and malformed responses cannot
|
one atomic store transaction; cancellation and malformed responses cannot
|
||||||
partially mutate the cache. Focused compatibility and injected-HTTP tests cover
|
partially mutate the cache. Focused compatibility and injected-HTTP tests cover
|
||||||
link correction, endpoint recording, error isolation, and metadata updates.
|
link correction, endpoint recording, error isolation, and metadata updates.
|
||||||
|
|
||||||
|
Native appearance state now tracks layered wearables and attachment points,
|
||||||
|
sends the inventory-backed wearable and attachment LLUDP messages, and exposes
|
||||||
|
worn queries by slot, item, and point. The client-owned Current Outfit Folder
|
||||||
|
service resolves inventory links, preserves layer descriptions, serializes
|
||||||
|
concurrent mutations through a cancellation-aware gate, and compensates failed
|
||||||
|
link or attachment replacement without publishing partial local state.
|
||||||
|
Composite policies make pure decisions from snapshots and receive committed
|
||||||
|
changes after synchronization is released. The behavior and transaction
|
||||||
|
boundaries are documented in [`docs/appearance.md`](docs/appearance.md).
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Generated by `python3 tools/generate_api_shims.py`; do not edit by hand.
|
|||||||
|
|
||||||
| Assembly | Types | Members | Status |
|
| Assembly | Types | Members | Status |
|
||||||
|---|---:|---:|---|
|
|---|---:|---:|---|
|
||||||
| `LibreMetaverse` | 2,711 | 27,281 | native implementation: 197 types / 15,177 members; remaining surface is callable failure-only shims |
|
| `LibreMetaverse` | 2,711 | 27,281 | native implementation: 200 types / 15,251 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.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.Imaging.Skia` | 1 | 3 | native implementation: 1 type / 3 members; no generated shims remain |
|
||||||
| `LibreMetaverse.LslTools` | 164 | 768 | callable failure-only shim |
|
| `LibreMetaverse.LslTools` | 164 | 768 | callable failure-only shim |
|
||||||
|
|||||||
964
crates/libremetaverse/src/appearance_manager.rs
Normal file
964
crates/libremetaverse/src/appearance_manager.rs
Normal file
@@ -0,0 +1,964 @@
|
|||||||
|
//! Native wearable and attachment state for `AppearanceManager`.
|
||||||
|
|
||||||
|
use crate::client_core::ClientWeakHandle;
|
||||||
|
use crate::packet_catalog::PacketType;
|
||||||
|
use crate::packets::{
|
||||||
|
AgentIsNowWearingPacket, AgentIsNowWearingPacketWearableDataBlock,
|
||||||
|
DetachAttachmentIntoInvPacket, RezSingleAttachmentFromInvPacket,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
AgentWearablesReplyEventArgs, AppearanceManagerWearableData, AppearanceSetEventArgs,
|
||||||
|
GridClient, InventoryBase, InventoryFolder, InventoryItem, InventoryObject,
|
||||||
|
InventoryObjectClass, InventoryWearable, Permissions, PrimitiveTextureEntry,
|
||||||
|
appearance::CurrentOutfitFolder,
|
||||||
|
};
|
||||||
|
use libremetaverse_types::compat::{CancellationToken, EventHandler, Subscription};
|
||||||
|
use libremetaverse_types::{
|
||||||
|
AssetType, AttachmentPoint, Error, FolderType, InventoryType, MultiValueDictionary, UUID,
|
||||||
|
WearableType,
|
||||||
|
};
|
||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, Ordering};
|
||||||
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
|
const ATTACHMENT_ADD: u8 = 0x80;
|
||||||
|
const MAX_WEARABLE_LAYERS: usize = 60;
|
||||||
|
const MAX_FOLDER_TRAVERSAL: usize = 256;
|
||||||
|
|
||||||
|
fn mutex<T>(lock: &Mutex<T>) -> std::sync::MutexGuard<'_, T> {
|
||||||
|
lock.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read<T>(lock: &RwLock<T>) -> std::sync::RwLockReadGuard<'_, T> {
|
||||||
|
lock.read()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<T>(lock: &RwLock<T>) -> std::sync::RwLockWriteGuard<'_, T> {
|
||||||
|
lock.write()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_cancelled(token: Option<&CancellationToken>) -> Result<(), Error> {
|
||||||
|
token.map_or(Ok(()), CancellationToken::throw_if_cancellation_requested)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EventRegistry<T> {
|
||||||
|
next_id: AtomicU64,
|
||||||
|
handlers: Arc<Mutex<HashMap<u64, EventHandler<T>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for EventRegistry<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
next_id: AtomicU64::new(1),
|
||||||
|
handlers: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> EventRegistry<T> {
|
||||||
|
fn subscribe(&self, handler: EventHandler<T>) -> Subscription {
|
||||||
|
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
|
||||||
|
mutex(&self.handlers).insert(id, handler);
|
||||||
|
let handlers = Arc::downgrade(&self.handlers);
|
||||||
|
Subscription::new(move || {
|
||||||
|
if let Some(handlers) = handlers.upgrade() {
|
||||||
|
mutex(&handlers).remove(&id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_with(&self, mut event: impl FnMut() -> T) {
|
||||||
|
let handlers: Vec<_> = mutex(&self.handlers).values().cloned().collect();
|
||||||
|
for handler in handlers {
|
||||||
|
handler(event());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
struct WearableRecord {
|
||||||
|
item_id: UUID,
|
||||||
|
asset_id: UUID,
|
||||||
|
asset_type: AssetType,
|
||||||
|
wearable_type: WearableType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WearableRecord {
|
||||||
|
fn from_item(item: &InventoryItem) -> Option<Self> {
|
||||||
|
if !matches!(item.asset_type(), AssetType::Bodypart | AssetType::Clothing) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let wearable = InventoryWearable { base: item.clone() };
|
||||||
|
Some(Self {
|
||||||
|
item_id: item.base.uuid(),
|
||||||
|
asset_id: item.asset_uuid(),
|
||||||
|
asset_type: item.asset_type(),
|
||||||
|
wearable_type: wearable.wearable_type(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn public(&self) -> AppearanceManagerWearableData {
|
||||||
|
AppearanceManagerWearableData {
|
||||||
|
asset: None,
|
||||||
|
asset_id: self.asset_id,
|
||||||
|
asset_type: self.asset_type,
|
||||||
|
item_id: self.item_id,
|
||||||
|
wearable_type: self.wearable_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
struct AttachmentRecord {
|
||||||
|
item: InventoryItem,
|
||||||
|
point: AttachmentPoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct AppearanceEvents {
|
||||||
|
agent_wearables_reply: EventRegistry<AgentWearablesReplyEventArgs>,
|
||||||
|
appearance_set: EventRegistry<AppearanceSetEventArgs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct AppearanceManagerInner {
|
||||||
|
client: ClientWeakHandle,
|
||||||
|
wearables: RwLock<Vec<WearableRecord>>,
|
||||||
|
attachments: RwLock<Vec<AttachmentRecord>>,
|
||||||
|
last_cof_version: AtomicI32,
|
||||||
|
busy: AtomicBool,
|
||||||
|
disposed: AtomicBool,
|
||||||
|
events: AppearanceEvents,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shared native manager. Public texture fields remain on the compatibility
|
||||||
|
/// wrapper; wearable and attachment state is shared by every client accessor.
|
||||||
|
pub struct AppearanceManager {
|
||||||
|
pub my_textures: PrimitiveTextureEntry,
|
||||||
|
pub my_visual_parameters: Vec<u8>,
|
||||||
|
inner: Arc<AppearanceManagerInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for AppearanceManager {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self::native_from_inner(Arc::clone(&self.inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for AppearanceManager {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("AppearanceManager")
|
||||||
|
.field("wearables", &read(&self.inner.wearables).len())
|
||||||
|
.field("attachments", &read(&self.inner.attachments).len())
|
||||||
|
.field("busy", &self.native_manager_busy())
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BusyGuard<'a>(&'a AtomicBool);
|
||||||
|
|
||||||
|
impl Drop for BusyGuard<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.store(false, Ordering::Release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppearanceManager {
|
||||||
|
pub(crate) fn native_new(client: Option<Arc<GridClient>>) -> Result<Self, Error> {
|
||||||
|
let client = client.ok_or(Error::ArgumentNull)?;
|
||||||
|
Ok(Self::native_from_inner(Arc::new(AppearanceManagerInner {
|
||||||
|
client: client.native_weak_handle(),
|
||||||
|
wearables: RwLock::new(Vec::new()),
|
||||||
|
attachments: RwLock::new(Vec::new()),
|
||||||
|
last_cof_version: AtomicI32::new(-1),
|
||||||
|
busy: AtomicBool::new(false),
|
||||||
|
disposed: AtomicBool::new(false),
|
||||||
|
events: AppearanceEvents::default(),
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_from_inner(inner: Arc<AppearanceManagerInner>) -> Self {
|
||||||
|
Self {
|
||||||
|
my_textures: PrimitiveTextureEntry {
|
||||||
|
default_texture: None,
|
||||||
|
face_textures: Vec::new(),
|
||||||
|
},
|
||||||
|
my_visual_parameters: Vec::new(),
|
||||||
|
inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_inner(&self) -> Arc<AppearanceManagerInner> {
|
||||||
|
Arc::clone(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client(&self) -> Result<GridClient, Error> {
|
||||||
|
if self.inner.disposed.load(Ordering::Acquire) {
|
||||||
|
return Err(Error::InvalidOperation);
|
||||||
|
}
|
||||||
|
self.inner.client.upgrade().ok_or(Error::InvalidOperation)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin(&self) -> Result<BusyGuard<'_>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
if self
|
||||||
|
.inner
|
||||||
|
.busy
|
||||||
|
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(Error::InvalidOperation);
|
||||||
|
}
|
||||||
|
Ok(BusyGuard(&self.inner.busy))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_subscribe_agent_wearables_reply(
|
||||||
|
&self,
|
||||||
|
handler: EventHandler<AgentWearablesReplyEventArgs>,
|
||||||
|
) -> Subscription {
|
||||||
|
self.inner.events.agent_wearables_reply.subscribe(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_subscribe_appearance_set(
|
||||||
|
&self,
|
||||||
|
handler: EventHandler<AppearanceSetEventArgs>,
|
||||||
|
) -> Subscription {
|
||||||
|
self.inner.events.appearance_set.subscribe(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_wraps)] // The mapped Dispose API is fallible.
|
||||||
|
pub(crate) fn native_dispose(&self) -> Result<(), Error> {
|
||||||
|
self.inner.disposed.store(true, Ordering::Release);
|
||||||
|
write(&self.inner.wearables).clear();
|
||||||
|
write(&self.inner.attachments).clear();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_manager_busy(&self) -> bool {
|
||||||
|
self.inner.busy.load(Ordering::Acquire)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_last_cof_version(&self) -> i32 {
|
||||||
|
self.inner.last_cof_version.load(Ordering::Acquire)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_wraps)] // The mapped method returns Result<(), Error>.
|
||||||
|
pub(crate) fn native_update_cof_version(&self, version: i32) -> Result<(), Error> {
|
||||||
|
self.inner
|
||||||
|
.last_cof_version
|
||||||
|
.fetch_max(version, Ordering::AcqRel);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_add_to_outfit(
|
||||||
|
&self,
|
||||||
|
items: Vec<InventoryItem>,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
let mut next = read(&self.inner.wearables).clone();
|
||||||
|
apply_wearables(&mut next, items, replace)?;
|
||||||
|
self.send_wearables(&next)?;
|
||||||
|
*write(&self.inner.wearables) = next;
|
||||||
|
drop(busy);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.appearance_set
|
||||||
|
.emit_with(|| AppearanceSetEventArgs);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.agent_wearables_reply
|
||||||
|
.emit_with(|| AgentWearablesReplyEventArgs);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_remove_from_outfit(&self, items: Vec<InventoryItem>) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
let ids: HashSet<_> = items.into_iter().map(|item| item.base.uuid()).collect();
|
||||||
|
let mut next = read(&self.inner.wearables).clone();
|
||||||
|
next.retain(|wearable| !ids.contains(&wearable.item_id));
|
||||||
|
self.send_wearables(&next)?;
|
||||||
|
*write(&self.inner.wearables) = next;
|
||||||
|
drop(busy);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.appearance_set
|
||||||
|
.emit_with(|| AppearanceSetEventArgs);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.agent_wearables_reply
|
||||||
|
.emit_with(|| AgentWearablesReplyEventArgs);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_async)] // Preserves the mapped asynchronous API boundary.
|
||||||
|
pub(crate) async fn native_replace_outfit(
|
||||||
|
&self,
|
||||||
|
items: Vec<InventoryItem>,
|
||||||
|
safe: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
let mut next = if safe {
|
||||||
|
read(&self.inner.wearables)
|
||||||
|
.iter()
|
||||||
|
.filter(|wearable| wearable.asset_type == AssetType::Bodypart)
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
apply_wearables(&mut next, items, false)?;
|
||||||
|
self.send_wearables(&next)?;
|
||||||
|
*write(&self.inner.wearables) = next;
|
||||||
|
drop(busy);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.appearance_set
|
||||||
|
.emit_with(|| AppearanceSetEventArgs);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.agent_wearables_reply
|
||||||
|
.emit_with(|| AgentWearablesReplyEventArgs);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn native_wear_outfit(
|
||||||
|
&self,
|
||||||
|
values: Vec<InventoryBase>,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let client = self.client()?;
|
||||||
|
let store = client
|
||||||
|
.native_inventory()?
|
||||||
|
.native_store()
|
||||||
|
.ok_or(Error::InvalidOperation)?;
|
||||||
|
let items: Vec<_> = values
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|value| store.native_item_value(value.uuid()))
|
||||||
|
.collect();
|
||||||
|
if replace {
|
||||||
|
self.native_replace_outfit(items, false).await
|
||||||
|
} else {
|
||||||
|
self.native_add_to_outfit(items, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_get_wearables(
|
||||||
|
&self,
|
||||||
|
) -> Result<Box<dyn Iterator<Item = AppearanceManagerWearableData>>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
let values: Vec<_> = read(&self.inner.wearables)
|
||||||
|
.iter()
|
||||||
|
.map(WearableRecord::public)
|
||||||
|
.collect();
|
||||||
|
Ok(Box::new(values.into_iter()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_get_wearable_assets(
|
||||||
|
&self,
|
||||||
|
wearable_type: WearableType,
|
||||||
|
) -> Result<Box<dyn Iterator<Item = UUID>>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
let values: Vec<_> = read(&self.inner.wearables)
|
||||||
|
.iter()
|
||||||
|
.filter(|wearable| wearable.wearable_type == wearable_type)
|
||||||
|
.map(|wearable| wearable.asset_id)
|
||||||
|
.collect();
|
||||||
|
Ok(Box::new(values.into_iter()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_get_wearables_by_type(
|
||||||
|
&self,
|
||||||
|
) -> Result<MultiValueDictionary<WearableType, AppearanceManagerWearableData>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
let result = MultiValueDictionary::new_with_constructor()?;
|
||||||
|
for wearable in read(&self.inner.wearables).iter() {
|
||||||
|
result.add(wearable.wearable_type, Some(wearable.public()))?;
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_is_item_worn(&self, item_id: UUID) -> Result<WearableType, Error> {
|
||||||
|
self.client()?;
|
||||||
|
Ok(read(&self.inner.wearables)
|
||||||
|
.iter()
|
||||||
|
.find(|wearable| wearable.item_id == item_id)
|
||||||
|
.map_or(WearableType::Invalid, |wearable| wearable.wearable_type))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_async)] // Preserves the mapped asynchronous API boundary.
|
||||||
|
pub(crate) async fn native_send_outfit(
|
||||||
|
&self,
|
||||||
|
cancellation_token: Option<CancellationToken>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
let busy = self.begin()?;
|
||||||
|
let snapshot = read(&self.inner.wearables).clone();
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
self.send_wearables(&snapshot)?;
|
||||||
|
drop(busy);
|
||||||
|
self.inner
|
||||||
|
.events
|
||||||
|
.appearance_set
|
||||||
|
.emit_with(|| AppearanceSetEventArgs);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_wearables(&self, wearables: &[WearableRecord]) -> Result<(), Error> {
|
||||||
|
let client = self.client()?;
|
||||||
|
let network = client.native_network()?;
|
||||||
|
let mut packet = AgentIsNowWearingPacket::new_with_constructor()?;
|
||||||
|
packet.agent_data.agent_id = network.native_agent_id();
|
||||||
|
packet.agent_data.session_id = network.native_session_id();
|
||||||
|
packet.wearable_data = wearables
|
||||||
|
.iter()
|
||||||
|
.map(|wearable| {
|
||||||
|
let mut block = AgentIsNowWearingPacketWearableDataBlock::new_with_constructor()?;
|
||||||
|
block.item_id = wearable.item_id;
|
||||||
|
block.wearable_type = wearable.wearable_type as u8;
|
||||||
|
Ok(block)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
|
send_generated(
|
||||||
|
&network,
|
||||||
|
PacketType::AgentIsNowWearing,
|
||||||
|
packet.to_bytes_with_method()?,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_attach(
|
||||||
|
&self,
|
||||||
|
item: InventoryItem,
|
||||||
|
point: AttachmentPoint,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
let name = item.base.name();
|
||||||
|
let description = item.description();
|
||||||
|
let permissions = item.permissions();
|
||||||
|
self.send_attach_packet(
|
||||||
|
item.base.uuid(),
|
||||||
|
item.base.owner_id(),
|
||||||
|
&name,
|
||||||
|
&description,
|
||||||
|
permissions,
|
||||||
|
item.flags(),
|
||||||
|
point,
|
||||||
|
replace,
|
||||||
|
)?;
|
||||||
|
self.record_attachment(item, point, replace);
|
||||||
|
drop(busy);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn native_attach_fields(
|
||||||
|
&self,
|
||||||
|
item_id: UUID,
|
||||||
|
owner_id: UUID,
|
||||||
|
name: String,
|
||||||
|
description: String,
|
||||||
|
permissions: Permissions,
|
||||||
|
item_flags: u32,
|
||||||
|
point: AttachmentPoint,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
self.send_attach_packet(
|
||||||
|
item_id,
|
||||||
|
owner_id,
|
||||||
|
&name,
|
||||||
|
&description,
|
||||||
|
permissions,
|
||||||
|
item_flags,
|
||||||
|
point,
|
||||||
|
replace,
|
||||||
|
)?;
|
||||||
|
let mut item = InventoryItem::new_with_inventory_type_uuid(InventoryType::OBJECT, item_id)?;
|
||||||
|
item.base.set_owner_id(owner_id);
|
||||||
|
item.base.set_name(name);
|
||||||
|
item.set_description(description);
|
||||||
|
item.set_permissions(permissions);
|
||||||
|
item.set_flags(item_flags);
|
||||||
|
item.set_asset_type(AssetType::Object);
|
||||||
|
self.record_attachment(item, point, replace);
|
||||||
|
drop(busy);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn send_attach_packet(
|
||||||
|
&self,
|
||||||
|
item_id: UUID,
|
||||||
|
owner_id: UUID,
|
||||||
|
name: &str,
|
||||||
|
description: &str,
|
||||||
|
permissions: Permissions,
|
||||||
|
item_flags: u32,
|
||||||
|
point: AttachmentPoint,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let client = self.client()?;
|
||||||
|
let network = client.native_network()?;
|
||||||
|
send_generated(
|
||||||
|
&network,
|
||||||
|
PacketType::RezSingleAttachmentFromInv,
|
||||||
|
attachment_packet_bytes(
|
||||||
|
network.native_agent_id(),
|
||||||
|
network.native_session_id(),
|
||||||
|
item_id,
|
||||||
|
owner_id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
permissions,
|
||||||
|
item_flags,
|
||||||
|
point,
|
||||||
|
replace,
|
||||||
|
)?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_attachment(&self, item: InventoryItem, point: AttachmentPoint, replace: bool) {
|
||||||
|
let mut attachments = write(&self.inner.attachments);
|
||||||
|
if replace && point != AttachmentPoint::Default {
|
||||||
|
attachments.retain(|existing| existing.point != point);
|
||||||
|
}
|
||||||
|
attachments.retain(|existing| existing.item.base.uuid() != item.base.uuid());
|
||||||
|
attachments.push(AttachmentRecord { item, point });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_add_attachments(
|
||||||
|
&self,
|
||||||
|
items: Vec<InventoryItem>,
|
||||||
|
remove_existing_first: bool,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
let existing = read(&self.inner.attachments).clone();
|
||||||
|
if remove_existing_first {
|
||||||
|
for attachment in &existing {
|
||||||
|
self.send_detach_packet(attachment.item.base.uuid())?;
|
||||||
|
write(&self.inner.attachments)
|
||||||
|
.retain(|candidate| candidate.item.base.uuid() != attachment.item.base.uuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for item in items {
|
||||||
|
let object = InventoryObject { base: item.clone() };
|
||||||
|
let point = object.attach_point();
|
||||||
|
let name = item.base.name();
|
||||||
|
let description = item.description();
|
||||||
|
self.send_attach_packet(
|
||||||
|
item.base.uuid(),
|
||||||
|
item.base.owner_id(),
|
||||||
|
&name,
|
||||||
|
&description,
|
||||||
|
item.permissions(),
|
||||||
|
item.flags(),
|
||||||
|
point,
|
||||||
|
replace,
|
||||||
|
)?;
|
||||||
|
self.record_attachment(item, point, replace);
|
||||||
|
}
|
||||||
|
drop(busy);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_detach(&self, item_id: UUID) -> Result<(), Error> {
|
||||||
|
let busy = self.begin()?;
|
||||||
|
self.send_detach_packet(item_id)?;
|
||||||
|
write(&self.inner.attachments).retain(|attachment| attachment.item.base.uuid() != item_id);
|
||||||
|
drop(busy);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_detach_packet(&self, item_id: UUID) -> Result<(), Error> {
|
||||||
|
let client = self.client()?;
|
||||||
|
let network = client.native_network()?;
|
||||||
|
let mut packet = DetachAttachmentIntoInvPacket::new_with_constructor()?;
|
||||||
|
packet.object_data.agent_id = network.native_agent_id();
|
||||||
|
packet.object_data.item_id = item_id;
|
||||||
|
send_generated(
|
||||||
|
&network,
|
||||||
|
PacketType::DetachAttachmentIntoInv,
|
||||||
|
packet.to_bytes_with_method()?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_get_attachments(
|
||||||
|
&self,
|
||||||
|
) -> Result<Box<dyn Iterator<Item = InventoryItem>>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
let values: Vec<_> = read(&self.inner.attachments)
|
||||||
|
.iter()
|
||||||
|
.map(|attachment| attachment.item.clone())
|
||||||
|
.collect();
|
||||||
|
Ok(Box::new(values.into_iter()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_async)] // Preserves the mapped asynchronous API boundary.
|
||||||
|
pub(crate) async fn native_get_attachments_by_point(
|
||||||
|
&self,
|
||||||
|
cancellation_token: Option<CancellationToken>,
|
||||||
|
) -> Result<MultiValueDictionary<AttachmentPoint, InventoryItem>, Error> {
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
self.client()?;
|
||||||
|
let result = MultiValueDictionary::new_with_constructor()?;
|
||||||
|
for attachment in read(&self.inner.attachments).iter() {
|
||||||
|
result.add(attachment.point, Some(attachment.item.clone()))?;
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_get_attachments_by_item(
|
||||||
|
&self,
|
||||||
|
) -> Result<HashMap<InventoryItem, AttachmentPoint>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
Ok(read(&self.inner.attachments)
|
||||||
|
.iter()
|
||||||
|
.map(|attachment| (attachment.item.clone(), attachment.point))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_get_attachments_by_id(
|
||||||
|
&self,
|
||||||
|
) -> Result<HashMap<UUID, AttachmentPoint>, Error> {
|
||||||
|
self.client()?;
|
||||||
|
Ok(read(&self.inner.attachments)
|
||||||
|
.iter()
|
||||||
|
.map(|attachment| (attachment.item.base.uuid(), attachment.point))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_is_item_attached(&self, item_id: UUID) -> bool {
|
||||||
|
read(&self.inner.attachments)
|
||||||
|
.iter()
|
||||||
|
.any(|attachment| attachment.item.base.uuid() == item_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_attachments_at(&self, point: AttachmentPoint) -> Vec<InventoryItem> {
|
||||||
|
read(&self.inner.attachments)
|
||||||
|
.iter()
|
||||||
|
.filter(|attachment| attachment.point == point)
|
||||||
|
.map(|attachment| attachment.item.clone())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_attachment_point(&self, item_id: UUID) -> Option<AttachmentPoint> {
|
||||||
|
read(&self.inner.attachments)
|
||||||
|
.iter()
|
||||||
|
.find(|attachment| attachment.item.base.uuid() == item_id)
|
||||||
|
.map(|attachment| attachment.point)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_async)] // Preserves the mapped asynchronous API boundary.
|
||||||
|
pub(crate) async fn native_get_current_outfit_folder(
|
||||||
|
&self,
|
||||||
|
cancellation_token: Option<CancellationToken>,
|
||||||
|
) -> Result<Option<InventoryFolder>, Error> {
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
let client = self.client()?;
|
||||||
|
let Some(store) = client.native_inventory()?.native_store() else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
let Some(id) = store.find_folder_for_type(FolderType::CurrentOutfit) else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
store.get_value_or_default_with_uuid_a7c63fbe(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_async)] // Preserves the mapped asynchronous API boundary.
|
||||||
|
pub(crate) async fn native_get_folder_wearables(
|
||||||
|
&self,
|
||||||
|
folder: UUID,
|
||||||
|
cancellation_token: Option<CancellationToken>,
|
||||||
|
) -> Result<(bool, Vec<InventoryWearable>, Vec<InventoryItem>), Error> {
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
let client = self.client()?;
|
||||||
|
let Some(store) = client.native_inventory()?.native_store() else {
|
||||||
|
return Ok((false, Vec::new(), Vec::new()));
|
||||||
|
};
|
||||||
|
let mut queue = VecDeque::from([folder]);
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
let mut scheduled = HashSet::from([folder]);
|
||||||
|
let mut wearables = Vec::new();
|
||||||
|
let mut attachments = Vec::new();
|
||||||
|
while let Some(folder_id) = queue.pop_front() {
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
if !visited.insert(folder_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Ok(contents) = store.get_contents_with_uuid(folder_id) else {
|
||||||
|
return Ok((false, wearables, attachments));
|
||||||
|
};
|
||||||
|
for value in contents {
|
||||||
|
if let Some(child) = value.as_any().downcast_ref::<InventoryFolder>() {
|
||||||
|
let child_id = child.base.uuid();
|
||||||
|
if scheduled.insert(child_id) {
|
||||||
|
if scheduled.len() > MAX_FOLDER_TRAVERSAL {
|
||||||
|
return Ok((false, wearables, attachments));
|
||||||
|
}
|
||||||
|
queue.push_back(child_id);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(item) = inventory_item(value.as_ref()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if matches!(item.asset_type(), AssetType::Bodypart | AssetType::Clothing) {
|
||||||
|
wearables.push(InventoryWearable { base: item });
|
||||||
|
} else if matches!(item.asset_type(), AssetType::Object | AssetType::Mesh) {
|
||||||
|
attachments.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((true, wearables, attachments))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn native_request_agent_worn(
|
||||||
|
&self,
|
||||||
|
cancellation_token: Option<CancellationToken>,
|
||||||
|
) -> Result<Vec<InventoryBase>, Error> {
|
||||||
|
let client = self.client()?;
|
||||||
|
let cof = CurrentOutfitFolder::new(Some(Arc::new(client)))?;
|
||||||
|
let links = cof
|
||||||
|
.get_current_outfit_links(cancellation_token.clone())
|
||||||
|
.await?;
|
||||||
|
check_cancelled(cancellation_token.as_ref())?;
|
||||||
|
Ok(links.into_iter().map(|item| item.base).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for AppearanceManagerWearableData {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.asset_id == other.asset_id
|
||||||
|
&& self.asset_type == other.asset_type
|
||||||
|
&& self.item_id == other.item_id
|
||||||
|
&& self.wearable_type == other.wearable_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for AppearanceManagerWearableData {}
|
||||||
|
|
||||||
|
pub(crate) const fn wearable_type_to_asset_type(wearable_type: WearableType) -> AssetType {
|
||||||
|
match wearable_type {
|
||||||
|
WearableType::Shape | WearableType::Skin | WearableType::Hair | WearableType::Eyes => {
|
||||||
|
AssetType::Bodypart
|
||||||
|
}
|
||||||
|
WearableType::Invalid => AssetType::Unknown,
|
||||||
|
_ => AssetType::Clothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_wearables(
|
||||||
|
current: &mut Vec<WearableRecord>,
|
||||||
|
items: Vec<InventoryItem>,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
for item in items {
|
||||||
|
let wearable = WearableRecord::from_item(&item).ok_or(Error::Argument)?;
|
||||||
|
if !seen.insert(wearable.item_id)
|
||||||
|
|| current
|
||||||
|
.iter()
|
||||||
|
.any(|existing| existing.item_id == wearable.item_id)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if replace || wearable.asset_type == AssetType::Bodypart {
|
||||||
|
current.retain(|existing| existing.wearable_type != wearable.wearable_type);
|
||||||
|
} else if current
|
||||||
|
.iter()
|
||||||
|
.filter(|existing| existing.wearable_type == wearable.wearable_type)
|
||||||
|
.count()
|
||||||
|
>= MAX_WEARABLE_LAYERS
|
||||||
|
{
|
||||||
|
return Err(Error::InvalidOperation);
|
||||||
|
}
|
||||||
|
current.push(wearable);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn attachment_packet_bytes(
|
||||||
|
agent_id: UUID,
|
||||||
|
session_id: UUID,
|
||||||
|
item_id: UUID,
|
||||||
|
owner_id: UUID,
|
||||||
|
name: &str,
|
||||||
|
description: &str,
|
||||||
|
permissions: Permissions,
|
||||||
|
item_flags: u32,
|
||||||
|
point: AttachmentPoint,
|
||||||
|
replace: bool,
|
||||||
|
) -> Result<Vec<u8>, Error> {
|
||||||
|
let mut packet = RezSingleAttachmentFromInvPacket::new_with_constructor()?;
|
||||||
|
packet.agent_data.agent_id = agent_id;
|
||||||
|
packet.agent_data.session_id = session_id;
|
||||||
|
packet.object_data.item_id = item_id;
|
||||||
|
packet.object_data.owner_id = owner_id;
|
||||||
|
packet.object_data.name = name.as_bytes().to_vec();
|
||||||
|
packet.object_data.description = description.as_bytes().to_vec();
|
||||||
|
packet.object_data.everyone_mask = permissions.everyone_mask.0;
|
||||||
|
packet.object_data.group_mask = permissions.group_mask.0;
|
||||||
|
packet.object_data.next_owner_mask = permissions.next_owner_mask.0;
|
||||||
|
packet.object_data.item_flags = item_flags;
|
||||||
|
packet.object_data.attachment_pt = (point as u8) | if replace { 0 } else { ATTACHMENT_ADD };
|
||||||
|
packet.to_bytes_with_method()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_generated(
|
||||||
|
network: &crate::NetworkManager,
|
||||||
|
packet_type: PacketType,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let simulator = network
|
||||||
|
.native_current_sim()
|
||||||
|
.ok_or(Error::InvalidOperation)?;
|
||||||
|
let length = i32::try_from(bytes.len()).map_err(|_| Error::Argument)?;
|
||||||
|
simulator.native_send_packet_data(bytes, length, packet_type, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inventory_item(value: &dyn InventoryObjectClass) -> Option<InventoryItem> {
|
||||||
|
if let Some(item) = value.as_any().downcast_ref::<InventoryItem>() {
|
||||||
|
return Some(item.clone());
|
||||||
|
}
|
||||||
|
macro_rules! item {
|
||||||
|
($kind:ty) => {
|
||||||
|
if let Some(item) = value.as_any().downcast_ref::<$kind>() {
|
||||||
|
return Some(item.base.clone());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
item!(crate::InventoryAnimation);
|
||||||
|
item!(crate::InventoryAttachment);
|
||||||
|
item!(crate::InventoryCallingCard);
|
||||||
|
item!(crate::InventoryCategory);
|
||||||
|
item!(crate::InventoryGesture);
|
||||||
|
item!(crate::InventoryLSL);
|
||||||
|
item!(crate::InventoryLandmark);
|
||||||
|
item!(crate::InventoryMaterial);
|
||||||
|
item!(crate::InventoryNotecard);
|
||||||
|
item!(crate::InventoryObject);
|
||||||
|
item!(crate::InventorySettings);
|
||||||
|
item!(crate::InventorySnapshot);
|
||||||
|
item!(crate::InventorySound);
|
||||||
|
item!(crate::InventoryTexture);
|
||||||
|
item!(crate::InventoryWearable);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn wearable(id: u64, wearable_type: WearableType, asset_type: AssetType) -> InventoryItem {
|
||||||
|
let mut wearable = InventoryWearable::new(UUID::new_with_u_int64(id).unwrap()).unwrap();
|
||||||
|
wearable.base.set_asset_type(asset_type);
|
||||||
|
wearable.base.set_inventory_type(InventoryType::WEARABLE);
|
||||||
|
wearable
|
||||||
|
.base
|
||||||
|
.set_asset_uuid(UUID::new_with_u_int64(id + 1_000).unwrap());
|
||||||
|
wearable.set_wearable_type(wearable_type);
|
||||||
|
wearable.base
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wearable_layers_are_bounded_and_bodyparts_replace_by_slot() {
|
||||||
|
let mut clothing = Vec::new();
|
||||||
|
apply_wearables(
|
||||||
|
&mut clothing,
|
||||||
|
(1..=60)
|
||||||
|
.map(|id| wearable(id, WearableType::Shirt, AssetType::Clothing))
|
||||||
|
.collect(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(clothing.len(), MAX_WEARABLE_LAYERS);
|
||||||
|
assert_eq!(
|
||||||
|
apply_wearables(
|
||||||
|
&mut clothing,
|
||||||
|
vec![wearable(61, WearableType::Shirt, AssetType::Clothing)],
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
Err(Error::InvalidOperation)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut bodyparts = Vec::new();
|
||||||
|
apply_wearables(
|
||||||
|
&mut bodyparts,
|
||||||
|
vec![wearable(100, WearableType::Shape, AssetType::Bodypart)],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
apply_wearables(
|
||||||
|
&mut bodyparts,
|
||||||
|
vec![wearable(101, WearableType::Shape, AssetType::Bodypart)],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(bodyparts.len(), 1);
|
||||||
|
assert_eq!(bodyparts[0].item_id, UUID::new_with_u_int64(101).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn attachment_packet_and_replacement_state_preserve_inventory_fields() {
|
||||||
|
let client = GridClient::new().unwrap();
|
||||||
|
let item_id = UUID::new_with_u_int64(500).unwrap();
|
||||||
|
let owner_id = UUID::new_with_u_int64(501).unwrap();
|
||||||
|
let permissions = Permissions::new(1, 2, 3, 4, 5).unwrap();
|
||||||
|
let mut item =
|
||||||
|
InventoryItem::new_with_inventory_type_uuid(InventoryType::OBJECT, item_id).unwrap();
|
||||||
|
item.base.set_owner_id(owner_id);
|
||||||
|
item.base.set_name("recording hat".into());
|
||||||
|
item.set_description("packet fields".into());
|
||||||
|
item.set_permissions(permissions);
|
||||||
|
item.set_flags(0x1234_5678);
|
||||||
|
item.set_asset_type(AssetType::Object);
|
||||||
|
|
||||||
|
let bytes = attachment_packet_bytes(
|
||||||
|
UUID::zero(),
|
||||||
|
UUID::zero(),
|
||||||
|
item_id,
|
||||||
|
owner_id,
|
||||||
|
"recording hat",
|
||||||
|
"packet fields",
|
||||||
|
permissions,
|
||||||
|
0x1234_5678,
|
||||||
|
AttachmentPoint::Skull,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut position = 0;
|
||||||
|
let packet =
|
||||||
|
RezSingleAttachmentFromInvPacket::new_with_bytes_int32(bytes, &mut position).unwrap();
|
||||||
|
assert_eq!(packet.object_data.item_id, item_id);
|
||||||
|
assert_eq!(packet.object_data.owner_id, owner_id);
|
||||||
|
assert_eq!(packet.object_data.name, b"recording hat");
|
||||||
|
assert_eq!(packet.object_data.description, b"packet fields");
|
||||||
|
assert_eq!(packet.object_data.everyone_mask, 2);
|
||||||
|
assert_eq!(packet.object_data.group_mask, 3);
|
||||||
|
assert_eq!(packet.object_data.next_owner_mask, 4);
|
||||||
|
assert_eq!(packet.object_data.item_flags, 0x1234_5678);
|
||||||
|
assert_eq!(
|
||||||
|
packet.object_data.attachment_pt,
|
||||||
|
(AttachmentPoint::Skull as u8) | ATTACHMENT_ADD
|
||||||
|
);
|
||||||
|
let manager = client.appearance();
|
||||||
|
manager.record_attachment(item, AttachmentPoint::Skull, false);
|
||||||
|
let replacement_id = UUID::new_with_u_int64(502).unwrap();
|
||||||
|
let mut replacement =
|
||||||
|
InventoryItem::new_with_inventory_type_uuid(InventoryType::OBJECT, replacement_id)
|
||||||
|
.unwrap();
|
||||||
|
replacement.set_permissions(permissions);
|
||||||
|
manager.record_attachment(replacement, AttachmentPoint::Skull, true);
|
||||||
|
let state = manager.native_get_attachments_by_id().unwrap();
|
||||||
|
assert_eq!(state.len(), 1);
|
||||||
|
assert_eq!(state.get(&replacement_id), Some(&AttachmentPoint::Skull));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -521,6 +521,7 @@ impl AssetTexture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct AssetWearable {
|
pub struct AssetWearable {
|
||||||
raw: RawAsset,
|
raw: RawAsset,
|
||||||
pub creator: UUID,
|
pub creator: UUID,
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ struct ClientRuntime {
|
|||||||
caps_rate_limiter: Mutex<crate::caps_http::CapsRateLimiter>,
|
caps_rate_limiter: Mutex<crate::caps_http::CapsRateLimiter>,
|
||||||
network_manager: Mutex<std::sync::Weak<crate::network_manager::NetworkManagerInner>>,
|
network_manager: Mutex<std::sync::Weak<crate::network_manager::NetworkManagerInner>>,
|
||||||
agent_manager: Mutex<std::sync::Weak<crate::agent_manager::AgentManagerInner>>,
|
agent_manager: Mutex<std::sync::Weak<crate::agent_manager::AgentManagerInner>>,
|
||||||
|
appearance_manager: Mutex<Option<Arc<crate::appearance_manager::AppearanceManagerInner>>>,
|
||||||
inventory_manager: Mutex<Option<Arc<crate::inventory_manager::InventoryManagerInner>>>,
|
inventory_manager: Mutex<Option<Arc<crate::inventory_manager::InventoryManagerInner>>>,
|
||||||
inventory_ais_client: Mutex<Option<crate::inventory_ais::InventoryAISClient>>,
|
inventory_ais_client: Mutex<Option<crate::inventory_ais::InventoryAISClient>>,
|
||||||
asset_manager: Mutex<Option<Arc<crate::asset_manager::AssetManagerInner>>>,
|
asset_manager: Mutex<Option<Arc<crate::asset_manager::AssetManagerInner>>>,
|
||||||
@@ -149,6 +150,7 @@ impl ClientRuntime {
|
|||||||
caps_rate_limiter: Mutex::new(caps_rate_limiter),
|
caps_rate_limiter: Mutex::new(caps_rate_limiter),
|
||||||
network_manager: Mutex::new(std::sync::Weak::new()),
|
network_manager: Mutex::new(std::sync::Weak::new()),
|
||||||
agent_manager: Mutex::new(std::sync::Weak::new()),
|
agent_manager: Mutex::new(std::sync::Weak::new()),
|
||||||
|
appearance_manager: Mutex::new(None),
|
||||||
inventory_manager: Mutex::new(None),
|
inventory_manager: Mutex::new(None),
|
||||||
inventory_ais_client: Mutex::new(None),
|
inventory_ais_client: Mutex::new(None),
|
||||||
asset_manager: Mutex::new(None),
|
asset_manager: Mutex::new(None),
|
||||||
@@ -449,6 +451,32 @@ impl GridClient {
|
|||||||
Ok(manager)
|
Ok(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn native_appearance(&self) -> Result<crate::AppearanceManager, crate::Error> {
|
||||||
|
let mut cached = self
|
||||||
|
.runtime
|
||||||
|
.appearance_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
|
if let Some(inner) = cached.as_ref() {
|
||||||
|
return Ok(
|
||||||
|
crate::appearance_manager::AppearanceManager::native_from_inner(Arc::clone(inner)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let manager =
|
||||||
|
crate::appearance_manager::AppearanceManager::native_new(Some(Arc::new(self.clone())))?;
|
||||||
|
*cached = Some(manager.native_inner());
|
||||||
|
Ok(manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub(crate) fn native_set_appearance(&mut self, value: crate::AppearanceManager) {
|
||||||
|
*self
|
||||||
|
.runtime
|
||||||
|
.appearance_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(value.native_inner());
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn native_assets(&self) -> Result<crate::AssetManager, crate::Error> {
|
pub(crate) fn native_assets(&self) -> Result<crate::AssetManager, crate::Error> {
|
||||||
let mut cached = self
|
let mut cached = self
|
||||||
.runtime
|
.runtime
|
||||||
|
|||||||
1457
crates/libremetaverse/src/current_outfit.rs
Normal file
1457
crates/libremetaverse/src/current_outfit.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2861,12 +2861,9 @@ impl AppearanceFlags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// C# type: `T:LibreMetaverse.AppearanceManager`.
|
/// C# type: `T:LibreMetaverse.AppearanceManager`.
|
||||||
pub struct AppearanceManager {
|
pub use crate::appearance_manager::AppearanceManager;
|
||||||
/// C# member: `F:LibreMetaverse.AppearanceManager.MyTextures`.
|
/// C# member: `F:LibreMetaverse.AppearanceManager.MyTextures`.
|
||||||
pub my_textures: libremetaverse::PrimitiveTextureEntry,
|
|
||||||
/// C# member: `F:LibreMetaverse.AppearanceManager.MyVisualParameters`.
|
/// C# member: `F:LibreMetaverse.AppearanceManager.MyVisualParameters`.
|
||||||
pub my_visual_parameters: Vec<u8>,
|
|
||||||
}
|
|
||||||
impl AppearanceManager {
|
impl AppearanceManager {
|
||||||
/// C# member: `E:LibreMetaverse.AppearanceManager.AgentWearablesReply`.
|
/// C# member: `E:LibreMetaverse.AppearanceManager.AgentWearablesReply`.
|
||||||
pub fn subscribe_agent_wearables_reply(
|
pub fn subscribe_agent_wearables_reply(
|
||||||
@@ -2875,16 +2872,14 @@ impl AppearanceManager {
|
|||||||
libremetaverse::AgentWearablesReplyEventArgs,
|
libremetaverse::AgentWearablesReplyEventArgs,
|
||||||
>,
|
>,
|
||||||
) -> libremetaverse_types::compat::Subscription {
|
) -> libremetaverse_types::compat::Subscription {
|
||||||
libremetaverse_types::unimplemented_api!(
|
self.native_subscribe_agent_wearables_reply(handler)
|
||||||
"E:LibreMetaverse.AppearanceManager.AgentWearablesReply"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `E:LibreMetaverse.AppearanceManager.AppearanceSet`.
|
/// C# member: `E:LibreMetaverse.AppearanceManager.AppearanceSet`.
|
||||||
pub fn subscribe_appearance_set(
|
pub fn subscribe_appearance_set(
|
||||||
&self,
|
&self,
|
||||||
handler: libremetaverse_types::compat::EventHandler<libremetaverse::AppearanceSetEventArgs>,
|
handler: libremetaverse_types::compat::EventHandler<libremetaverse::AppearanceSetEventArgs>,
|
||||||
) -> libremetaverse_types::compat::Subscription {
|
) -> libremetaverse_types::compat::Subscription {
|
||||||
libremetaverse_types::unimplemented_api!("E:LibreMetaverse.AppearanceManager.AppearanceSet")
|
self.native_subscribe_appearance_set(handler)
|
||||||
}
|
}
|
||||||
/// C# member: `E:LibreMetaverse.AppearanceManager.CachedBakesReply`.
|
/// C# member: `E:LibreMetaverse.AppearanceManager.CachedBakesReply`.
|
||||||
pub fn subscribe_cached_bakes_reply(
|
pub fn subscribe_cached_bakes_reply(
|
||||||
@@ -3025,9 +3020,7 @@ impl AppearanceManager {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
||||||
) -> Result<Self, crate::Error> {
|
) -> Result<Self, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
crate::appearance_manager::AppearanceManager::native_new(client)
|
||||||
"M:LibreMetaverse.AppearanceManager.#ctor(LibreMetaverse.GridClient)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.AddAttachments(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Boolean)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.AddAttachments(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Boolean)`.
|
||||||
pub fn add_attachments(
|
pub fn add_attachments(
|
||||||
@@ -3036,9 +3029,7 @@ impl AppearanceManager {
|
|||||||
remove_existing_first: bool,
|
remove_existing_first: bool,
|
||||||
replace: Option<bool>,
|
replace: Option<bool>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_attachments(attachments, remove_existing_first, replace.unwrap_or(false))
|
||||||
"M:LibreMetaverse.AppearanceManager.AddAttachments(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Boolean)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.AddToOutfit(LibreMetaverse.InventoryItem,System.Boolean)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.AddToOutfit(LibreMetaverse.InventoryItem,System.Boolean)`.
|
||||||
pub fn add_to_outfit_with_inventory_item_boolean(
|
pub fn add_to_outfit_with_inventory_item_boolean(
|
||||||
@@ -3046,9 +3037,7 @@ impl AppearanceManager {
|
|||||||
wearable_item: libremetaverse::InventoryItem,
|
wearable_item: libremetaverse::InventoryItem,
|
||||||
replace: Option<bool>,
|
replace: Option<bool>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_to_outfit(vec![wearable_item], replace.unwrap_or(false))
|
||||||
"M:LibreMetaverse.AppearanceManager.AddToOutfit(LibreMetaverse.InventoryItem,System.Boolean)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.AddToOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.AddToOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)`.
|
||||||
pub fn add_to_outfit_with_list_boolean(
|
pub fn add_to_outfit_with_list_boolean(
|
||||||
@@ -3056,9 +3045,7 @@ impl AppearanceManager {
|
|||||||
wearable_items: Vec<libremetaverse::InventoryItem>,
|
wearable_items: Vec<libremetaverse::InventoryItem>,
|
||||||
replace: Option<bool>,
|
replace: Option<bool>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_to_outfit(wearable_items, replace.unwrap_or(false))
|
||||||
"M:LibreMetaverse.AppearanceManager.AddToOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.ApplyArchetype(LibreMetaverse.GenepoolArchetype)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.ApplyArchetype(LibreMetaverse.GenepoolArchetype)`.
|
||||||
pub async fn apply_archetype(
|
pub async fn apply_archetype(
|
||||||
@@ -3076,9 +3063,7 @@ impl AppearanceManager {
|
|||||||
attach_point: libremetaverse_types::AttachmentPoint,
|
attach_point: libremetaverse_types::AttachmentPoint,
|
||||||
replace: Option<bool>,
|
replace: Option<bool>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_attach(item, attach_point, replace.unwrap_or(false))
|
||||||
"M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.UUID,LibreMetaverse.UUID,System.String,System.String,LibreMetaverse.Permissions,System.UInt32,LibreMetaverse.AttachmentPoint,System.Boolean)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.UUID,LibreMetaverse.UUID,System.String,System.String,LibreMetaverse.Permissions,System.UInt32,LibreMetaverse.AttachmentPoint,System.Boolean)`.
|
||||||
pub fn attach_with_uuid_uuid_string_string_permissions_u_int32_attachment_point_boolean(
|
pub fn attach_with_uuid_uuid_string_string_permissions_u_int32_attachment_point_boolean(
|
||||||
@@ -3092,8 +3077,15 @@ impl AppearanceManager {
|
|||||||
attach_point: libremetaverse_types::AttachmentPoint,
|
attach_point: libremetaverse_types::AttachmentPoint,
|
||||||
replace: Option<bool>,
|
replace: Option<bool>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_attach_fields(
|
||||||
"M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.UUID,LibreMetaverse.UUID,System.String,System.String,LibreMetaverse.Permissions,System.UInt32,LibreMetaverse.AttachmentPoint,System.Boolean)",
|
item_id,
|
||||||
|
owner_id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
perms,
|
||||||
|
item_flags,
|
||||||
|
attach_point,
|
||||||
|
replace.unwrap_or(false),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.BakeTypeToAgentTextureIndex(LibreMetaverse.BakeType)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.BakeTypeToAgentTextureIndex(LibreMetaverse.BakeType)`.
|
||||||
@@ -3136,28 +3128,24 @@ impl AppearanceManager {
|
|||||||
&self,
|
&self,
|
||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_detach(item.base.uuid())
|
||||||
"M:LibreMetaverse.AppearanceManager.Detach(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.Detach(LibreMetaverse.UUID)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.Detach(LibreMetaverse.UUID)`.
|
||||||
pub fn detach_with_uuid(
|
pub fn detach_with_uuid(
|
||||||
&self,
|
&self,
|
||||||
item_id: libremetaverse_types::UUID,
|
item_id: libremetaverse_types::UUID,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_detach(item_id)
|
||||||
"M:LibreMetaverse.AppearanceManager.Detach(LibreMetaverse.UUID)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.Dispose`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.Dispose`.
|
||||||
pub fn dispose(&self) -> Result<(), crate::Error> {
|
pub fn dispose(&self) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented("M:LibreMetaverse.AppearanceManager.Dispose")
|
self.native_dispose()
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachments`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachments`.
|
||||||
pub fn get_attachments(
|
pub fn get_attachments(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Box<dyn Iterator<Item = libremetaverse::InventoryItem>>, crate::Error> {
|
) -> Result<Box<dyn Iterator<Item = libremetaverse::InventoryItem>>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented("M:LibreMetaverse.AppearanceManager.GetAttachments")
|
self.native_get_attachments()
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachmentsByAttachmentPointAsync(System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachmentsByAttachmentPointAsync(System.Threading.CancellationToken)`.
|
||||||
pub async fn get_attachments_by_attachment_point(
|
pub async fn get_attachments_by_attachment_point(
|
||||||
@@ -3170,9 +3158,8 @@ impl AppearanceManager {
|
|||||||
>,
|
>,
|
||||||
crate::Error,
|
crate::Error,
|
||||||
> {
|
> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_attachments_by_point(cancellation_token)
|
||||||
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByAttachmentPointAsync(System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachmentsByInventoryItem`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachmentsByInventoryItem`.
|
||||||
pub fn get_attachments_by_inventory_item(
|
pub fn get_attachments_by_inventory_item(
|
||||||
@@ -3184,9 +3171,7 @@ impl AppearanceManager {
|
|||||||
>,
|
>,
|
||||||
crate::Error,
|
crate::Error,
|
||||||
> {
|
> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_attachments_by_item()
|
||||||
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByInventoryItem",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachmentsByItemId`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetAttachmentsByItemId`.
|
||||||
pub fn get_attachments_by_item_id(
|
pub fn get_attachments_by_item_id(
|
||||||
@@ -3198,9 +3183,7 @@ impl AppearanceManager {
|
|||||||
>,
|
>,
|
||||||
crate::Error,
|
crate::Error,
|
||||||
> {
|
> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_attachments_by_id()
|
||||||
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByItemId",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetColorFromParams(System.Collections.Generic.List{LibreMetaverse.AppearanceManager.ColorParamInfo})`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetColorFromParams(System.Collections.Generic.List{LibreMetaverse.AppearanceManager.ColorParamInfo})`.
|
||||||
pub fn get_color_from_params(
|
pub fn get_color_from_params(
|
||||||
@@ -3215,9 +3198,8 @@ impl AppearanceManager {
|
|||||||
&self,
|
&self,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<Option<libremetaverse::InventoryFolder>, crate::Error> {
|
) -> Result<Option<libremetaverse::InventoryFolder>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_current_outfit_folder(cancellation_token)
|
||||||
"M:LibreMetaverse.AppearanceManager.GetCurrentOutfitFolderAsync(System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetCurrentParamValues`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetCurrentParamValues`.
|
||||||
pub fn get_current_param_values(
|
pub fn get_current_param_values(
|
||||||
@@ -3240,25 +3222,22 @@ impl AppearanceManager {
|
|||||||
),
|
),
|
||||||
crate::Error,
|
crate::Error,
|
||||||
> {
|
> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_folder_wearables(folder, cancellation_token)
|
||||||
"M:LibreMetaverse.AppearanceManager.GetFolderWearablesAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetWearableAssets(LibreMetaverse.WearableType)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetWearableAssets(LibreMetaverse.WearableType)`.
|
||||||
pub fn get_wearable_assets(
|
pub fn get_wearable_assets(
|
||||||
&self,
|
&self,
|
||||||
type_: libremetaverse_types::WearableType,
|
type_: libremetaverse_types::WearableType,
|
||||||
) -> Result<Box<dyn Iterator<Item = libremetaverse_types::UUID>>, crate::Error> {
|
) -> Result<Box<dyn Iterator<Item = libremetaverse_types::UUID>>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_wearable_assets(type_)
|
||||||
"M:LibreMetaverse.AppearanceManager.GetWearableAssets(LibreMetaverse.WearableType)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetWearables`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetWearables`.
|
||||||
pub fn get_wearables(
|
pub fn get_wearables(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Box<dyn Iterator<Item = libremetaverse::AppearanceManagerWearableData>>, crate::Error>
|
) -> Result<Box<dyn Iterator<Item = libremetaverse::AppearanceManagerWearableData>>, crate::Error>
|
||||||
{
|
{
|
||||||
libremetaverse_types::not_implemented("M:LibreMetaverse.AppearanceManager.GetWearables")
|
self.native_get_wearables()
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.GetWearablesByType`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.GetWearablesByType`.
|
||||||
pub fn get_wearables_by_type(
|
pub fn get_wearables_by_type(
|
||||||
@@ -3270,27 +3249,21 @@ impl AppearanceManager {
|
|||||||
>,
|
>,
|
||||||
crate::Error,
|
crate::Error,
|
||||||
> {
|
> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_wearables_by_type()
|
||||||
"M:LibreMetaverse.AppearanceManager.GetWearablesByType",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.InventoryItem)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.InventoryItem)`.
|
||||||
pub fn is_item_worn_with_inventory_item(
|
pub fn is_item_worn_with_inventory_item(
|
||||||
&self,
|
&self,
|
||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
) -> Result<libremetaverse_types::WearableType, crate::Error> {
|
) -> Result<libremetaverse_types::WearableType, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_is_item_worn(item.base.uuid())
|
||||||
"M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.UUID)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.UUID)`.
|
||||||
pub fn is_item_worn_with_uuid(
|
pub fn is_item_worn_with_uuid(
|
||||||
&self,
|
&self,
|
||||||
item_id: libremetaverse_types::UUID,
|
item_id: libremetaverse_types::UUID,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
Ok(self.native_is_item_worn(item_id)? != libremetaverse_types::WearableType::Invalid)
|
||||||
"M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.UUID)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.MakeAppearancePacket`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.MakeAppearancePacket`.
|
||||||
pub fn make_appearance_packet(
|
pub fn make_appearance_packet(
|
||||||
@@ -3322,27 +3295,21 @@ impl AppearanceManager {
|
|||||||
&self,
|
&self,
|
||||||
wearable_item: libremetaverse::InventoryItem,
|
wearable_item: libremetaverse::InventoryItem,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_remove_from_outfit(vec![wearable_item])
|
||||||
"M:LibreMetaverse.AppearanceManager.RemoveFromOutfit(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.RemoveFromOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem})`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.RemoveFromOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem})`.
|
||||||
pub fn remove_from_outfit_with_list(
|
pub fn remove_from_outfit_with_list(
|
||||||
&self,
|
&self,
|
||||||
wearable_items: Vec<libremetaverse::InventoryItem>,
|
wearable_items: Vec<libremetaverse::InventoryItem>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_remove_from_outfit(wearable_items)
|
||||||
"M:LibreMetaverse.AppearanceManager.RemoveFromOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem})",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem})`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem})`.
|
||||||
pub async fn replace_outfit_with_list(
|
pub async fn replace_outfit_with_list(
|
||||||
&self,
|
&self,
|
||||||
wearable_items: Vec<libremetaverse::InventoryItem>,
|
wearable_items: Vec<libremetaverse::InventoryItem>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_replace_outfit(wearable_items, false).await
|
||||||
"M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem})",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)`.
|
||||||
pub async fn replace_outfit_with_list_boolean(
|
pub async fn replace_outfit_with_list_boolean(
|
||||||
@@ -3350,18 +3317,14 @@ impl AppearanceManager {
|
|||||||
wearable_items: Vec<libremetaverse::InventoryItem>,
|
wearable_items: Vec<libremetaverse::InventoryItem>,
|
||||||
safe: bool,
|
safe: bool,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_replace_outfit(wearable_items, safe).await
|
||||||
"M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.RequestAgentWornAsync(System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.RequestAgentWornAsync(System.Threading.CancellationToken)`.
|
||||||
pub async fn request_agent_worn(
|
pub async fn request_agent_worn(
|
||||||
&self,
|
&self,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<Vec<libremetaverse::InventoryBase>, crate::Error> {
|
) -> Result<Vec<libremetaverse::InventoryBase>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_request_agent_worn(cancellation_token).await
|
||||||
"M:LibreMetaverse.AppearanceManager.RequestAgentWornAsync(System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.RequestCachedBakes`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.RequestCachedBakes`.
|
||||||
pub fn request_cached_bakes(&self) -> Result<(), crate::Error> {
|
pub fn request_cached_bakes(&self) -> Result<(), crate::Error> {
|
||||||
@@ -3383,9 +3346,7 @@ impl AppearanceManager {
|
|||||||
&self,
|
&self,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_send_outfit(cancellation_token).await
|
||||||
"M:LibreMetaverse.AppearanceManager.SendOutfitToCurrentSimulatorAsync(System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.ServerBakingRegion`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.ServerBakingRegion`.
|
||||||
pub fn server_baking_region(&self) -> Result<bool, crate::Error> {
|
pub fn server_baking_region(&self) -> Result<bool, crate::Error> {
|
||||||
@@ -3398,9 +3359,7 @@ impl AppearanceManager {
|
|||||||
&mut self,
|
&mut self,
|
||||||
cof_version: i32,
|
cof_version: i32,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_update_cof_version(cof_version)
|
||||||
"M:LibreMetaverse.AppearanceManager.UpdateLastReceivedCOFVersion(System.Int32)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.WearOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryBase},System.Boolean)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.WearOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryBase},System.Boolean)`.
|
||||||
pub async fn wear_outfit(
|
pub async fn wear_outfit(
|
||||||
@@ -3408,45 +3367,37 @@ impl AppearanceManager {
|
|||||||
wearables: Vec<libremetaverse::InventoryBase>,
|
wearables: Vec<libremetaverse::InventoryBase>,
|
||||||
replace_items: bool,
|
replace_items: bool,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_wear_outfit(wearables, replace_items).await
|
||||||
"M:LibreMetaverse.AppearanceManager.WearOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryBase},System.Boolean)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.WearableTypeToAssetType(LibreMetaverse.WearableType)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.WearableTypeToAssetType(LibreMetaverse.WearableType)`.
|
||||||
pub fn wearable_type_to_asset_type(
|
pub fn wearable_type_to_asset_type(
|
||||||
type_: libremetaverse_types::WearableType,
|
type_: libremetaverse_types::WearableType,
|
||||||
) -> Result<libremetaverse_types::AssetType, crate::Error> {
|
) -> Result<libremetaverse_types::AssetType, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
Ok(crate::appearance_manager::wearable_type_to_asset_type(
|
||||||
"M:LibreMetaverse.AppearanceManager.WearableTypeToAssetType(LibreMetaverse.WearableType)",
|
type_,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.InventoryItem)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.InventoryItem)`.
|
||||||
pub fn is_item_attached_with_inventory_item(
|
pub fn is_item_attached_with_inventory_item(
|
||||||
&self,
|
&self,
|
||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
Ok(self.native_is_item_attached(item.base.uuid()))
|
||||||
"M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.UUID)`.
|
/// C# member: `M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.UUID)`.
|
||||||
pub fn is_item_attached_with_uuid(
|
pub fn is_item_attached_with_uuid(
|
||||||
&self,
|
&self,
|
||||||
key: libremetaverse_types::UUID,
|
key: libremetaverse_types::UUID,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
Ok(self.native_is_item_attached(key))
|
||||||
"M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.UUID)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.AppearanceManager.LastUpdateReceivedCOFVersion`.
|
/// C# member: `P:LibreMetaverse.AppearanceManager.LastUpdateReceivedCOFVersion`.
|
||||||
pub fn last_update_received_cof_version(&self) -> i32 {
|
pub fn last_update_received_cof_version(&self) -> i32 {
|
||||||
libremetaverse_types::unimplemented_api!(
|
self.native_last_cof_version()
|
||||||
"P:LibreMetaverse.AppearanceManager.LastUpdateReceivedCOFVersion"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.AppearanceManager.ManagerBusy`.
|
/// C# member: `P:LibreMetaverse.AppearanceManager.ManagerBusy`.
|
||||||
pub fn manager_busy(&self) -> bool {
|
pub fn manager_busy(&self) -> bool {
|
||||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AppearanceManager.ManagerBusy")
|
self.native_manager_busy()
|
||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.AppearanceManager.TextureProvider`.
|
/// C# member: `P:LibreMetaverse.AppearanceManager.TextureProvider`.
|
||||||
pub fn texture_provider(&self) -> std::sync::Arc<dyn libremetaverse::IBakingTextureProvider> {
|
pub fn texture_provider(&self) -> std::sync::Arc<dyn libremetaverse::IBakingTextureProvider> {
|
||||||
@@ -3507,6 +3458,7 @@ impl AppearanceManagerTextureData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// C# type: `T:LibreMetaverse.AppearanceManager.WearableData`.
|
/// C# type: `T:LibreMetaverse.AppearanceManager.WearableData`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct AppearanceManagerWearableData {
|
pub struct AppearanceManagerWearableData {
|
||||||
/// C# member: `F:LibreMetaverse.AppearanceManager.WearableData.Asset`.
|
/// C# member: `F:LibreMetaverse.AppearanceManager.WearableData.Asset`.
|
||||||
pub asset: Option<libremetaverse::assets::AssetWearable>,
|
pub asset: Option<libremetaverse::assets::AssetWearable>,
|
||||||
@@ -8786,11 +8738,14 @@ impl GridClient {
|
|||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.GridClient.Appearance`.
|
/// C# member: `P:LibreMetaverse.GridClient.Appearance`.
|
||||||
pub fn appearance(&self) -> libremetaverse::AppearanceManager {
|
pub fn appearance(&self) -> libremetaverse::AppearanceManager {
|
||||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Appearance")
|
/* native client-core implementation */
|
||||||
|
self.native_appearance()
|
||||||
|
.unwrap_or_else(|_| panic!("failed to construct AppearanceManager"))
|
||||||
}
|
}
|
||||||
/// Setter for C# member: `P:LibreMetaverse.GridClient.Appearance`.
|
/// Setter for C# member: `P:LibreMetaverse.GridClient.Appearance`.
|
||||||
pub fn set_appearance(&mut self, value: libremetaverse::AppearanceManager) {
|
pub fn set_appearance(&mut self, value: libremetaverse::AppearanceManager) {
|
||||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.GridClient.Appearance")
|
/* native client-core implementation */
|
||||||
|
self.native_set_appearance(value)
|
||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.GridClient.Assets`.
|
/// C# member: `P:LibreMetaverse.GridClient.Assets`.
|
||||||
pub fn assets(&self) -> libremetaverse::AssetManager {
|
pub fn assets(&self) -> libremetaverse::AssetManager {
|
||||||
@@ -14722,9 +14677,13 @@ impl NameValue {
|
|||||||
sendto_type: libremetaverse::NameValueSendtoType,
|
sendto_type: libremetaverse::NameValueSendtoType,
|
||||||
value: libremetaverse_types::compat::Object,
|
value: libremetaverse_types::compat::Object,
|
||||||
) -> Result<Self, crate::Error> {
|
) -> Result<Self, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
Ok(crate::NameValue {
|
||||||
"M:LibreMetaverse.NameValue.#ctor(System.String,LibreMetaverse.NameValue.ValueType,LibreMetaverse.NameValue.ClassType,LibreMetaverse.NameValue.SendtoType,System.Object)",
|
class_: class_type,
|
||||||
)
|
name,
|
||||||
|
sendto: sendto_type,
|
||||||
|
type_: value_type,
|
||||||
|
value: Some(value),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.NameValue.Equals(LibreMetaverse.NameValue)`.
|
/// C# member: `M:LibreMetaverse.NameValue.Equals(LibreMetaverse.NameValue)`.
|
||||||
pub fn equals_with_name_value(&self, other: libremetaverse::NameValue) -> bool {
|
pub fn equals_with_name_value(&self, other: libremetaverse::NameValue) -> bool {
|
||||||
@@ -18572,7 +18531,7 @@ pub struct Primitive {
|
|||||||
impl Primitive {
|
impl Primitive {
|
||||||
/// C# member: `M:LibreMetaverse.Primitive.#ctor`.
|
/// C# member: `M:LibreMetaverse.Primitive.#ctor`.
|
||||||
pub fn new_with_constructor() -> Result<Self, crate::Error> {
|
pub fn new_with_constructor() -> Result<Self, crate::Error> {
|
||||||
libremetaverse_types::not_implemented("M:LibreMetaverse.Primitive.#ctor")
|
Ok(crate::current_outfit::primitive_defaults())
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Primitive.#ctor(LibreMetaverse.Primitive)`.
|
/// C# member: `M:LibreMetaverse.Primitive.#ctor(LibreMetaverse.Primitive)`.
|
||||||
pub fn new_with_primitive(prim: libremetaverse::Primitive) -> Result<Self, crate::Error> {
|
pub fn new_with_primitive(prim: libremetaverse::Primitive) -> Result<Self, crate::Error> {
|
||||||
@@ -23074,13 +23033,11 @@ pub mod animesh {
|
|||||||
|
|
||||||
pub mod appearance {
|
pub mod appearance {
|
||||||
/// C# type: `T:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy`.
|
/// C# type: `T:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy`.
|
||||||
pub struct CompositeCurrentOutfitPolicy;
|
pub use crate::current_outfit::CompositeCurrentOutfitPolicy;
|
||||||
impl CompositeCurrentOutfitPolicy {
|
impl CompositeCurrentOutfitPolicy {
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.#ctor`.
|
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.#ctor`.
|
||||||
pub fn new() -> Result<Self, crate::Error> {
|
pub fn new() -> Result<Self, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
crate::current_outfit::CompositeCurrentOutfitPolicy::native_new()
|
||||||
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.#ctor",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
||||||
pub fn add_policy(
|
pub fn add_policy(
|
||||||
@@ -23089,27 +23046,21 @@ pub mod appearance {
|
|||||||
std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
||||||
>,
|
>,
|
||||||
) -> Result<&Self, crate::Error> {
|
) -> Result<&Self, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_policy(policy_to_add)
|
||||||
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanAttach(LibreMetaverse.InventoryItem)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanAttach(LibreMetaverse.InventoryItem)`.
|
||||||
pub fn can_attach(
|
pub fn can_attach(
|
||||||
&self,
|
&self,
|
||||||
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_can_attach(item)
|
||||||
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanAttach(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)`.
|
||||||
pub fn can_detach(
|
pub fn can_detach(
|
||||||
&self,
|
&self,
|
||||||
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_can_detach(item)
|
||||||
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
||||||
pub fn remove_policy(
|
pub fn remove_policy(
|
||||||
@@ -23118,9 +23069,7 @@ pub mod appearance {
|
|||||||
std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
||||||
>,
|
>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_remove_policy(policy_to_remove)
|
||||||
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)`.
|
||||||
pub async fn report_item_change(
|
pub async fn report_item_change(
|
||||||
@@ -23129,23 +23078,19 @@ pub mod appearance {
|
|||||||
removed_items: Option<std::sync::Arc<Vec<libremetaverse::InventoryItem>>>,
|
removed_items: Option<std::sync::Arc<Vec<libremetaverse::InventoryItem>>>,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_report_item_change(added_items, removed_items, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl libremetaverse::appearance::ICurrentOutfitPolicy for CompositeCurrentOutfitPolicy {}
|
|
||||||
|
|
||||||
/// C# type: `T:LibreMetaverse.Appearance.CurrentOutfitFolder`.
|
/// C# type: `T:LibreMetaverse.Appearance.CurrentOutfitFolder`.
|
||||||
pub struct CurrentOutfitFolder;
|
pub use crate::current_outfit::CurrentOutfitFolder;
|
||||||
impl CurrentOutfitFolder {
|
impl CurrentOutfitFolder {
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.#ctor(LibreMetaverse.GridClient)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.#ctor(LibreMetaverse.GridClient)`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
client: Option<std::sync::Arc<libremetaverse::GridClient>>,
|
||||||
) -> Result<Self, crate::Error> {
|
) -> Result<Self, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
crate::current_outfit::CurrentOutfitFolder::native_new(client)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.#ctor(LibreMetaverse.GridClient)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
||||||
pub fn add_policy(
|
pub fn add_policy(
|
||||||
@@ -23155,9 +23100,7 @@ pub mod appearance {
|
|||||||
std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
||||||
crate::Error,
|
crate::Error,
|
||||||
> {
|
> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_policy(policy_to_add)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(LibreMetaverse.InventoryItem,System.Boolean,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(LibreMetaverse.InventoryItem,System.Boolean,System.Threading.CancellationToken)`.
|
||||||
pub async fn add_to_outfit_with_inventory_item_boolean_cancellation_token(
|
pub async fn add_to_outfit_with_inventory_item_boolean_cancellation_token(
|
||||||
@@ -23166,9 +23109,8 @@ pub mod appearance {
|
|||||||
replace: bool,
|
replace: bool,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_to_outfit(vec![item], replace, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(LibreMetaverse.InventoryItem,System.Boolean,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Threading.CancellationToken)`.
|
||||||
pub async fn add_to_outfit_with_list_boolean_cancellation_token(
|
pub async fn add_to_outfit_with_list_boolean_cancellation_token(
|
||||||
@@ -23177,9 +23119,8 @@ pub mod appearance {
|
|||||||
replace: bool,
|
replace: bool,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_add_to_outfit(requested_items_to_add, replace, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AttachAsync(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.AttachAsync(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean,System.Threading.CancellationToken)`.
|
||||||
pub async fn attach(
|
pub async fn attach(
|
||||||
@@ -23189,9 +23130,8 @@ pub mod appearance {
|
|||||||
replace: bool,
|
replace: bool,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_attach(item, point, replace, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AttachAsync(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanAttachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanAttachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
||||||
pub async fn can_attach_item(
|
pub async fn can_attach_item(
|
||||||
@@ -23199,9 +23139,7 @@ pub mod appearance {
|
|||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_can_attach_item(item, cancellation_token).await
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanAttachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanDetachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanDetachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
||||||
pub async fn can_detach_item(
|
pub async fn can_detach_item(
|
||||||
@@ -23209,9 +23147,7 @@ pub mod appearance {
|
|||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_can_detach_item(item, cancellation_token).await
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanDetachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.DetachAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.DetachAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
||||||
pub async fn detach(
|
pub async fn detach(
|
||||||
@@ -23219,15 +23155,11 @@ pub mod appearance {
|
|||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_detach(item, cancellation_token).await
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.DetachAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.Dispose`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.Dispose`.
|
||||||
pub fn dispose(&self) -> Result<(), crate::Error> {
|
pub fn dispose(&self) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_dispose()
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.Dispose",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.FetchParentAsync(LibreMetaverse.InventoryBase,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.FetchParentAsync(LibreMetaverse.InventoryBase,System.Threading.CancellationToken)`.
|
||||||
pub async fn fetch_parent(
|
pub async fn fetch_parent(
|
||||||
@@ -23235,26 +23167,21 @@ pub mod appearance {
|
|||||||
item: libremetaverse::InventoryBase,
|
item: libremetaverse::InventoryBase,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<Option<libremetaverse::InventoryBase>, crate::Error> {
|
) -> Result<Option<libremetaverse::InventoryBase>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_fetch_parent(item, cancellation_token).await
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.FetchParentAsync(LibreMetaverse.InventoryBase,System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetAttachmentItemID(LibreMetaverse.Primitive)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetAttachmentItemID(LibreMetaverse.Primitive)`.
|
||||||
pub fn get_attachment_item_id(
|
pub fn get_attachment_item_id(
|
||||||
prim: libremetaverse::Primitive,
|
prim: libremetaverse::Primitive,
|
||||||
) -> Result<libremetaverse_types::UUID, crate::Error> {
|
) -> Result<libremetaverse_types::UUID, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
crate::current_outfit::CurrentOutfitFolder::native_get_attachment_item_id(prim)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetAttachmentItemID(LibreMetaverse.Primitive)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetCurrentOutfitLinksAsync(System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetCurrentOutfitLinksAsync(System.Threading.CancellationToken)`.
|
||||||
pub async fn get_current_outfit_links(
|
pub async fn get_current_outfit_links(
|
||||||
&self,
|
&self,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<Vec<libremetaverse::InventoryItem>, crate::Error> {
|
) -> Result<Vec<libremetaverse::InventoryItem>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_current_outfit_links(cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetCurrentOutfitLinksAsync(System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetWornAtAsync(LibreMetaverse.WearableType,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetWornAtAsync(LibreMetaverse.WearableType,System.Threading.CancellationToken)`.
|
||||||
pub async fn get_worn_at(
|
pub async fn get_worn_at(
|
||||||
@@ -23262,9 +23189,7 @@ pub mod appearance {
|
|||||||
type_: libremetaverse_types::WearableType,
|
type_: libremetaverse_types::WearableType,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<Vec<libremetaverse::InventoryItem>, crate::Error> {
|
) -> Result<Vec<libremetaverse::InventoryItem>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_get_worn_at(type_, cancellation_token).await
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetWornAtAsync(LibreMetaverse.WearableType,System.Threading.CancellationToken)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.IsObjectDescendentOfAsync(LibreMetaverse.InventoryBase,LibreMetaverse.UUID,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.IsObjectDescendentOfAsync(LibreMetaverse.InventoryBase,LibreMetaverse.UUID,System.Threading.CancellationToken)`.
|
||||||
pub async fn is_object_descendent_of(
|
pub async fn is_object_descendent_of(
|
||||||
@@ -23273,9 +23198,8 @@ pub mod appearance {
|
|||||||
parent_id: libremetaverse_types::UUID,
|
parent_id: libremetaverse_types::UUID,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_is_object_descendent_of(item, parent_id, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.IsObjectDescendentOfAsync(LibreMetaverse.InventoryBase,LibreMetaverse.UUID,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)`.
|
||||||
pub async fn remove_from_outfit_with_inventory_item_cancellation_token(
|
pub async fn remove_from_outfit_with_inventory_item_cancellation_token(
|
||||||
@@ -23283,9 +23207,8 @@ pub mod appearance {
|
|||||||
item: libremetaverse::InventoryItem,
|
item: libremetaverse::InventoryItem,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_remove_from_outfit(vec![item], cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)`.
|
||||||
pub async fn remove_from_outfit_with_list_cancellation_token(
|
pub async fn remove_from_outfit_with_list_cancellation_token(
|
||||||
@@ -23293,18 +23216,15 @@ pub mod appearance {
|
|||||||
requested_items_to_remove: Vec<libremetaverse::InventoryItem>,
|
requested_items_to_remove: Vec<libremetaverse::InventoryItem>,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_remove_from_outfit(requested_items_to_remove, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)`.
|
||||||
pub fn remove_policy(
|
pub fn remove_policy(
|
||||||
&self,
|
&self,
|
||||||
policy_to_remove: std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
policy_to_remove: std::sync::Arc<dyn libremetaverse::appearance::ICurrentOutfitPolicy>,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_remove_policy(policy_to_remove)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.ReplaceOutfitAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.ReplaceOutfitAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)`.
|
||||||
pub async fn replace_outfit(
|
pub async fn replace_outfit(
|
||||||
@@ -23312,36 +23232,27 @@ pub mod appearance {
|
|||||||
new_outfit_folder_id: libremetaverse_types::UUID,
|
new_outfit_folder_id: libremetaverse_types::UUID,
|
||||||
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
cancellation_token: Option<libremetaverse_types::compat::CancellationToken>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_replace_outfit(new_outfit_folder_id, cancellation_token)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.ReplaceOutfitAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)",
|
.await
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.ResolveInventoryLink(LibreMetaverse.InventoryItem)`.
|
/// C# member: `M:LibreMetaverse.Appearance.CurrentOutfitFolder.ResolveInventoryLink(LibreMetaverse.InventoryItem)`.
|
||||||
pub fn resolve_inventory_link(
|
pub fn resolve_inventory_link(
|
||||||
&self,
|
&self,
|
||||||
item_link: std::sync::Arc<libremetaverse::InventoryItem>,
|
item_link: std::sync::Arc<libremetaverse::InventoryItem>,
|
||||||
) -> Result<Option<std::sync::Arc<libremetaverse::InventoryItem>>, crate::Error> {
|
) -> Result<Option<std::sync::Arc<libremetaverse::InventoryItem>>, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
self.native_resolve_inventory_link(item_link)
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.ResolveInventoryLink(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF`.
|
/// C# member: `P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF`.
|
||||||
pub fn cof(&self) -> Option<libremetaverse::InventoryFolder> {
|
pub fn cof(&self) -> Option<libremetaverse::InventoryFolder> {
|
||||||
libremetaverse_types::unimplemented_api!(
|
self.native_cof()
|
||||||
"P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// Setter for C# member: `P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF`.
|
/// Setter for C# member: `P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF`.
|
||||||
pub fn set_cof(&mut self, value: Option<libremetaverse::InventoryFolder>) {
|
pub fn set_cof(&mut self, value: Option<libremetaverse::InventoryFolder>) {
|
||||||
libremetaverse_types::unimplemented_api!(
|
self.native_set_cof(value)
|
||||||
"P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `P:LibreMetaverse.Appearance.CurrentOutfitFolder.MaxClothingLayers`.
|
/// C# member: `P:LibreMetaverse.Appearance.CurrentOutfitFolder.MaxClothingLayers`.
|
||||||
pub fn max_clothing_layers(&self) -> i32 {
|
pub fn max_clothing_layers(&self) -> i32 {
|
||||||
libremetaverse_types::unimplemented_api!(
|
crate::current_outfit::MAX_CLOTHING_LAYERS
|
||||||
"P:LibreMetaverse.Appearance.CurrentOutfitFolder.MaxClothingLayers"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23352,18 +23263,14 @@ pub mod appearance {
|
|||||||
&self,
|
&self,
|
||||||
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
crate::current_outfit::default_policy_decision(item)
|
||||||
"M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.CanAttach(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)`.
|
/// C# member: `M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)`.
|
||||||
fn can_detach(
|
fn can_detach(
|
||||||
&self,
|
&self,
|
||||||
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
item: Option<std::sync::Arc<libremetaverse::InventoryItem>>,
|
||||||
) -> Result<bool, crate::Error> {
|
) -> Result<bool, crate::Error> {
|
||||||
libremetaverse_types::not_implemented(
|
crate::current_outfit::default_policy_decision(item)
|
||||||
"M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// C# member: `M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)`.
|
/// C# member: `M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)`.
|
||||||
fn report_item_change(
|
fn report_item_change(
|
||||||
@@ -23374,11 +23281,11 @@ pub mod appearance {
|
|||||||
) -> std::pin::Pin<
|
) -> std::pin::Pin<
|
||||||
Box<dyn std::future::Future<Output = Result<(), crate::Error>> + Send + '_>,
|
Box<dyn std::future::Future<Output = Result<(), crate::Error>> + Send + '_>,
|
||||||
> {
|
> {
|
||||||
Box::pin(async {
|
crate::current_outfit::default_policy_report(
|
||||||
libremetaverse_types::not_implemented(
|
added_items,
|
||||||
"M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)",
|
removed_items,
|
||||||
|
cancellation_token,
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use libremetaverse_types::{
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::{self, File, OpenOptions};
|
use std::fs::{self, File, OpenOptions};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, RwLock, Weak};
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
@@ -306,6 +307,24 @@ impl PartialEq for InventoryItem {
|
|||||||
|
|
||||||
impl Eq for InventoryItem {}
|
impl Eq for InventoryItem {}
|
||||||
|
|
||||||
|
impl Hash for InventoryItem {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.base.hash(state);
|
||||||
|
self.asset_uuid.hash(state);
|
||||||
|
self.asset_type.hash(state);
|
||||||
|
self.inventory_type.hash(state);
|
||||||
|
self.description.hash(state);
|
||||||
|
self.group_id.hash(state);
|
||||||
|
self.group_owned.hash(state);
|
||||||
|
self.sale_price.hash(state);
|
||||||
|
self.sale_type.hash(state);
|
||||||
|
self.flags.hash(state);
|
||||||
|
self.creation_date.hash(state);
|
||||||
|
self.last_owner_id.hash(state);
|
||||||
|
self.permissions.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl InventoryItem {
|
impl InventoryItem {
|
||||||
fn with_type(inventory_type: InventoryType, uuid: UUID) -> Self {
|
fn with_type(inventory_type: InventoryType, uuid: UUID) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ mod attention_catalog;
|
|||||||
mod agent_manager;
|
mod agent_manager;
|
||||||
mod agent_messages;
|
mod agent_messages;
|
||||||
mod agent_movement;
|
mod agent_movement;
|
||||||
|
mod appearance_manager;
|
||||||
mod asset_cache;
|
mod asset_cache;
|
||||||
mod asset_manager;
|
mod asset_manager;
|
||||||
mod asset_material;
|
mod asset_material;
|
||||||
@@ -15,6 +16,7 @@ mod bit_pack;
|
|||||||
mod caps;
|
mod caps;
|
||||||
mod caps_http;
|
mod caps_http;
|
||||||
mod client_core;
|
mod client_core;
|
||||||
|
mod current_outfit;
|
||||||
mod download_manager;
|
mod download_manager;
|
||||||
mod event_queue;
|
mod event_queue;
|
||||||
mod gesture;
|
mod gesture;
|
||||||
@@ -122,41 +124,6 @@ impl animesh::AnimeshPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
trait CofLinkItem {
|
|
||||||
fn inventory_item(&self) -> &InventoryItem;
|
|
||||||
fn wearable_type(&self) -> Option<libremetaverse_types::WearableType>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CofLinkItem for InventoryWearable {
|
|
||||||
fn inventory_item(&self) -> &InventoryItem {
|
|
||||||
&self.base
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wearable_type(&self) -> Option<libremetaverse_types::WearableType> {
|
|
||||||
Some(self.wearable_type())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CofLinkItem for InventoryObject {
|
|
||||||
fn inventory_item(&self) -> &InventoryItem {
|
|
||||||
&self.base
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wearable_type(&self) -> Option<libremetaverse_types::WearableType> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::unused_self, dead_code)]
|
|
||||||
impl appearance::CurrentOutfitFolder {
|
|
||||||
fn get_cof_link_description(&self, _item: &dyn CofLinkItem) -> Result<String, Error> {
|
|
||||||
libremetaverse_types::not_implemented(
|
|
||||||
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetCofLinkDescription(LibreMetaverse.InventoryItem)",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)] // Internal C# surface consumed by InventoryManager workflows.
|
#[allow(dead_code)] // Internal C# surface consumed by InventoryManager workflows.
|
||||||
impl InventoryAISClient {
|
impl InventoryAISClient {
|
||||||
async fn create_inventory_links(
|
async fn create_inventory_links(
|
||||||
|
|||||||
61
docs/appearance.md
Normal file
61
docs/appearance.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Appearance, wearables, and the Current Outfit Folder
|
||||||
|
|
||||||
|
`AppearanceManager` owns the client-visible wearable and attachment snapshots.
|
||||||
|
Wearables retain their inventory item, asset, asset type, and wearable slot. A
|
||||||
|
clothing slot accepts at most 60 ordered layers; body parts are single-value
|
||||||
|
slots and replace an existing value of the same type. Sending the outfit emits
|
||||||
|
the native `AgentIsNowWearing` packet from a snapshot, then publishes the
|
||||||
|
appearance event after the send. Wearable reply and appearance subscribers are
|
||||||
|
also snapshotted before invocation, so no state or subscriber lock is held
|
||||||
|
during a callback.
|
||||||
|
|
||||||
|
Attachment calls preserve the inventory owner, name, description, permission
|
||||||
|
masks, flags, and requested attachment point in
|
||||||
|
`RezSingleAttachmentFromInv`. Add versus replace is encoded in the attachment
|
||||||
|
point field, and replace removes only objects at the selected non-default
|
||||||
|
point. `DetachAttachmentIntoInv` is keyed by inventory item ID. Queries expose
|
||||||
|
the same state by item, item ID, and attachment point.
|
||||||
|
|
||||||
|
## Current Outfit Folder ownership
|
||||||
|
|
||||||
|
`CurrentOutfitFolder` discovers the `CurrentOutfit` system folder from the
|
||||||
|
inventory store unless an explicit folder has been supplied. Its contents are
|
||||||
|
links: link UUIDs identify COF entries and link asset UUIDs identify the worn
|
||||||
|
inventory objects. Resolution first consults committed local link targets and
|
||||||
|
then the inventory store. This keeps successful mutations immediately
|
||||||
|
queryable while an asynchronous inventory reply is still being reconciled.
|
||||||
|
|
||||||
|
Clothing link descriptions encode the wearable type followed by a two-digit
|
||||||
|
layer number. Add chooses the first free layer, preserves existing layers, and
|
||||||
|
rejects a 61st layer. Replace removes the selected wearable type before
|
||||||
|
allocating its new layers. Body-part and attachment descriptions remain empty,
|
||||||
|
matching the reference link format. Folder ancestry and recursive outfit
|
||||||
|
discovery are cycle-safe and bounded to 256 nodes.
|
||||||
|
|
||||||
|
Mutations pass through a one-permit asynchronous operation gate. Waiting for
|
||||||
|
the gate is cancellation-aware, but the gate is not an inventory/state lock;
|
||||||
|
network awaits never retain a synchronous lock. Cancellation is checked while
|
||||||
|
planning and before committing. Once a commit begins, it completes or runs its
|
||||||
|
compensation before reporting the result, preventing a cancellation race from
|
||||||
|
leaving a half-written outfit.
|
||||||
|
|
||||||
|
Outfit changes create replacement links before removing old links. If removal
|
||||||
|
fails, new links are removed and old link descriptions are recreated. Attach
|
||||||
|
creates its COF link before executing the rez request; replacement removes the
|
||||||
|
displaced links only after the new attachment succeeds. A later failure
|
||||||
|
detaches the new item and restores displaced attachments. Detach similarly
|
||||||
|
restores the attachment if its COF link cannot be removed. The local shadow is
|
||||||
|
changed only after those network steps succeed.
|
||||||
|
|
||||||
|
`ICurrentOutfitPolicy` remains a pure decision/reporting boundary. Composite
|
||||||
|
policies use a stable subscriber snapshot, consult every policy for attach and
|
||||||
|
detach decisions, and invoke reports in registration order. Policy locks are
|
||||||
|
released before callbacks and committed changes are reported exactly once.
|
||||||
|
|
||||||
|
Focused compatibility coverage lives in `current_outfit_folder_semantics`,
|
||||||
|
`current_outfit_policy_semantics`, the COF link-description cases, and the
|
||||||
|
issue-relevant appearance cases. Native recording fakes additionally prove
|
||||||
|
create/remove compensation, create-before-attach ordering, replacement state,
|
||||||
|
layer preservation, and cancellation before backend interaction. Texture
|
||||||
|
baking, visual-parameter synthesis, and texture upload are a separate
|
||||||
|
appearance pipeline and are not owned by this service slice.
|
||||||
87
tools/check_milestone_09_issue_65.py
Normal file
87
tools/check_milestone_09_issue_65.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Audit issue 65's wearable, attachment, COF, and policy boundary."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
import generate_api_shims
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
APPEARANCE = ROOT / "crates" / "libremetaverse" / "src" / "appearance_manager.rs"
|
||||||
|
COF = ROOT / "crates" / "libremetaverse" / "src" / "current_outfit.rs"
|
||||||
|
CLIENT = ROOT / "crates" / "libremetaverse" / "src" / "client_core.rs"
|
||||||
|
COMPAT = ROOT / "tests" / "compat" / "tests"
|
||||||
|
LINK_TESTS = ROOT / "crates" / "libremetaverse" / "src" / "batch_link_internal_semantics.rs"
|
||||||
|
DOC = ROOT / "docs" / "appearance.md"
|
||||||
|
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")
|
||||||
|
|
||||||
|
REQUIRED_TYPES = {
|
||||||
|
"T:LibreMetaverse.AppearanceManager",
|
||||||
|
"T:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy",
|
||||||
|
"T:LibreMetaverse.Appearance.CurrentOutfitFolder",
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRED_MEMBERS = {
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AttachAsync(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean,System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.DetachAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetCurrentOutfitLinksAsync(System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetWornAtAsync(LibreMetaverse.WearableType,System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.ReplaceOutfitAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByAttachmentPointAsync(System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetFolderWearablesAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.SendOutfitToCurrentSimulatorAsync(System.Threading.CancellationToken)",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def require_markers(path: Path, markers: tuple[str, ...]) -> None:
|
||||||
|
text = path.read_text()
|
||||||
|
missing = [marker for marker in markers if marker not in text]
|
||||||
|
if missing:
|
||||||
|
raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing))
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
native = set(generate_api_shims.NATIVE_TYPES) | set(generate_api_shims.NATIVE_DECLARATIONS)
|
||||||
|
missing_types = sorted(REQUIRED_TYPES - native)
|
||||||
|
if missing_types:
|
||||||
|
raise SystemExit("issue 65 native types missing: " + ", ".join(missing_types))
|
||||||
|
missing_members = sorted(REQUIRED_MEMBERS - set(generate_api_shims.NATIVE_MEMBER_BODIES))
|
||||||
|
if missing_members:
|
||||||
|
raise SystemExit("issue 65 native members missing: " + ", ".join(missing_members))
|
||||||
|
for source in (APPEARANCE, COF):
|
||||||
|
if STUB_RE.search(source.read_text()):
|
||||||
|
raise SystemExit(f"issue 65 owned Rust stubs remain in {source.name}")
|
||||||
|
|
||||||
|
require_markers(APPEARANCE, (
|
||||||
|
"MAX_WEARABLE_LAYERS", "MAX_FOLDER_TRAVERSAL",
|
||||||
|
"AgentIsNowWearing", "RezSingleAttachmentFromInv",
|
||||||
|
"DetachAttachmentIntoInv", "permissions.everyone_mask",
|
||||||
|
"native_attachments_at", "emit_with",
|
||||||
|
"attachment_packet_and_replacement_state_preserve_inventory_fields",
|
||||||
|
"wearable_layers_are_bounded_and_bodyparts_replace_by_slot",
|
||||||
|
))
|
||||||
|
require_markers(COF, (
|
||||||
|
"MAX_CLOTHING_LAYERS", "MAX_ANCESTRY_DEPTH", "shadow_links",
|
||||||
|
"tokio::sync::Semaphore", "token.cancelled()", "snapshot()",
|
||||||
|
"create_links", "remove_links", "native_resolve_inventory_link",
|
||||||
|
"failed_replace_keeps_old_shadow_state_and_records_compensation",
|
||||||
|
"attach_creates_cof_link_before_network_execution",
|
||||||
|
"attachment_replace_removes_displaced_link_after_new_attachment",
|
||||||
|
"cancelled_operation_does_not_reach_backend",
|
||||||
|
))
|
||||||
|
require_markers(CLIENT, ("native_appearance", "native_set_appearance"))
|
||||||
|
require_markers(COMPAT / "current_outfit_folder_semantics.rs", ("parity-case", "get_current_outfit_links"))
|
||||||
|
require_markers(COMPAT / "current_outfit_policy_semantics.rs", ("parity-case", "report_item_change"))
|
||||||
|
require_markers(COMPAT / "appearance_semantics.rs", ("wearable_type_to_asset_type", "last_update_received_cof_version"))
|
||||||
|
require_markers(LINK_TESTS, ("get_cof_link_description", "clothing_wearable"))
|
||||||
|
require_markers(DOC, ("60", "256", "create replacement links before removing old links", "no state or subscriber lock", "compensation"))
|
||||||
|
print("issue 65 audit: native wearable/attachment state, transactional COF links, policy snapshots, cancellation, documentation, and focused fake/compatibility evidence are present")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -291,6 +291,9 @@ NATIVE_TYPES = {
|
|||||||
# hand-written, while its fixed public methods remain generator-audited.
|
# hand-written, while its fixed public methods remain generator-audited.
|
||||||
NATIVE_DECLARATIONS = {
|
NATIVE_DECLARATIONS = {
|
||||||
"T:LibreMetaverse.AgentManager": "crate::agent_manager::AgentManager",
|
"T:LibreMetaverse.AgentManager": "crate::agent_manager::AgentManager",
|
||||||
|
"T:LibreMetaverse.AppearanceManager": "crate::appearance_manager::AppearanceManager",
|
||||||
|
"T:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy": "crate::current_outfit::CompositeCurrentOutfitPolicy",
|
||||||
|
"T:LibreMetaverse.Appearance.CurrentOutfitFolder": "crate::current_outfit::CurrentOutfitFolder",
|
||||||
"T:LibreMetaverse.GridClient": "crate::client_core::GridClient",
|
"T:LibreMetaverse.GridClient": "crate::client_core::GridClient",
|
||||||
"T:LibreMetaverse.InventoryManager": "crate::inventory_manager::InventoryManager",
|
"T:LibreMetaverse.InventoryManager": "crate::inventory_manager::InventoryManager",
|
||||||
"T:LibreMetaverse.InventoryAISClient": "crate::inventory_ais::InventoryAISClient",
|
"T:LibreMetaverse.InventoryAISClient": "crate::inventory_ais::InventoryAISClient",
|
||||||
@@ -302,6 +305,146 @@ NATIVE_DECLARATIONS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NATIVE_MEMBER_BODIES = {
|
NATIVE_MEMBER_BODIES = {
|
||||||
|
"M:LibreMetaverse.NameValue.#ctor(System.String,LibreMetaverse.NameValue.ValueType,LibreMetaverse.NameValue.ClassType,LibreMetaverse.NameValue.SendtoType,System.Object)":
|
||||||
|
"Ok(crate::NameValue { class_: class_type, name, sendto: sendto_type, type_: value_type, value: Some(value) })",
|
||||||
|
"M:LibreMetaverse.Primitive.#ctor":
|
||||||
|
"Ok(crate::current_outfit::primitive_defaults())",
|
||||||
|
"M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.CanAttach(LibreMetaverse.InventoryItem)":
|
||||||
|
"crate::current_outfit::default_policy_decision(item)",
|
||||||
|
"M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)":
|
||||||
|
"crate::current_outfit::default_policy_decision(item)",
|
||||||
|
"M:LibreMetaverse.Appearance.ICurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)":
|
||||||
|
"crate::current_outfit::default_policy_report(added_items, removed_items, cancellation_token)",
|
||||||
|
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.#ctor":
|
||||||
|
"crate::current_outfit::CompositeCurrentOutfitPolicy::native_new()",
|
||||||
|
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)":
|
||||||
|
"self.native_add_policy(policy_to_add)",
|
||||||
|
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanAttach(LibreMetaverse.InventoryItem)":
|
||||||
|
"self.native_can_attach(item)",
|
||||||
|
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.CanDetach(LibreMetaverse.InventoryItem)":
|
||||||
|
"self.native_can_detach(item)",
|
||||||
|
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)":
|
||||||
|
"self.native_remove_policy(policy_to_remove)",
|
||||||
|
"M:LibreMetaverse.Appearance.CompositeCurrentOutfitPolicy.ReportItemChangeAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)":
|
||||||
|
"self.native_report_item_change(added_items, removed_items, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.#ctor(LibreMetaverse.GridClient)":
|
||||||
|
"crate::current_outfit::CurrentOutfitFolder::native_new(client)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddPolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)":
|
||||||
|
"self.native_add_policy(policy_to_add)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(LibreMetaverse.InventoryItem,System.Boolean,System.Threading.CancellationToken)":
|
||||||
|
"self.native_add_to_outfit(vec![item], replace, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AddToOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Threading.CancellationToken)":
|
||||||
|
"self.native_add_to_outfit(requested_items_to_add, replace, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.AttachAsync(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean,System.Threading.CancellationToken)":
|
||||||
|
"self.native_attach(item, point, replace, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanAttachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)":
|
||||||
|
"self.native_can_attach_item(item, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.CanDetachItemAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)":
|
||||||
|
"self.native_can_detach_item(item, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.DetachAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)":
|
||||||
|
"self.native_detach(item, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.Dispose":
|
||||||
|
"self.native_dispose()",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.FetchParentAsync(LibreMetaverse.InventoryBase,System.Threading.CancellationToken)":
|
||||||
|
"self.native_fetch_parent(item, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetAttachmentItemID(LibreMetaverse.Primitive)":
|
||||||
|
"crate::current_outfit::CurrentOutfitFolder::native_get_attachment_item_id(prim)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetCurrentOutfitLinksAsync(System.Threading.CancellationToken)":
|
||||||
|
"self.native_get_current_outfit_links(cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.GetWornAtAsync(LibreMetaverse.WearableType,System.Threading.CancellationToken)":
|
||||||
|
"self.native_get_worn_at(type_, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.IsObjectDescendentOfAsync(LibreMetaverse.InventoryBase,LibreMetaverse.UUID,System.Threading.CancellationToken)":
|
||||||
|
"self.native_is_object_descendent_of(item, parent_id, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(LibreMetaverse.InventoryItem,System.Threading.CancellationToken)":
|
||||||
|
"self.native_remove_from_outfit(vec![item], cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemoveFromOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Threading.CancellationToken)":
|
||||||
|
"self.native_remove_from_outfit(requested_items_to_remove, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.RemovePolicy(LibreMetaverse.Appearance.ICurrentOutfitPolicy)":
|
||||||
|
"self.native_remove_policy(policy_to_remove)",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.ReplaceOutfitAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)":
|
||||||
|
"self.native_replace_outfit(new_outfit_folder_id, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.Appearance.CurrentOutfitFolder.ResolveInventoryLink(LibreMetaverse.InventoryItem)":
|
||||||
|
"self.native_resolve_inventory_link(item_link)",
|
||||||
|
"P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF":
|
||||||
|
"self.native_cof()",
|
||||||
|
"P:LibreMetaverse.Appearance.CurrentOutfitFolder.COF#set":
|
||||||
|
"self.native_set_cof(value)",
|
||||||
|
"P:LibreMetaverse.Appearance.CurrentOutfitFolder.MaxClothingLayers":
|
||||||
|
"crate::current_outfit::MAX_CLOTHING_LAYERS",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.#ctor(LibreMetaverse.GridClient)":
|
||||||
|
"crate::appearance_manager::AppearanceManager::native_new(client)",
|
||||||
|
"E:LibreMetaverse.AppearanceManager.AgentWearablesReply":
|
||||||
|
"self.native_subscribe_agent_wearables_reply(handler)",
|
||||||
|
"E:LibreMetaverse.AppearanceManager.AppearanceSet":
|
||||||
|
"self.native_subscribe_appearance_set(handler)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.AddAttachments(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean,System.Boolean)":
|
||||||
|
"self.native_add_attachments(attachments, remove_existing_first, replace.unwrap_or(false))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.AddToOutfit(LibreMetaverse.InventoryItem,System.Boolean)":
|
||||||
|
"self.native_add_to_outfit(vec![wearable_item], replace.unwrap_or(false))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.AddToOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)":
|
||||||
|
"self.native_add_to_outfit(wearable_items, replace.unwrap_or(false))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.InventoryItem,LibreMetaverse.AttachmentPoint,System.Boolean)":
|
||||||
|
"self.native_attach(item, attach_point, replace.unwrap_or(false))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.Attach(LibreMetaverse.UUID,LibreMetaverse.UUID,System.String,System.String,LibreMetaverse.Permissions,System.UInt32,LibreMetaverse.AttachmentPoint,System.Boolean)":
|
||||||
|
"self.native_attach_fields(item_id, owner_id, name, description, perms, item_flags, attach_point, replace.unwrap_or(false))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.Detach(LibreMetaverse.InventoryItem)":
|
||||||
|
"self.native_detach(item.base.uuid())",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.Detach(LibreMetaverse.UUID)":
|
||||||
|
"self.native_detach(item_id)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.Dispose":
|
||||||
|
"self.native_dispose()",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetAttachments":
|
||||||
|
"self.native_get_attachments()",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByAttachmentPointAsync(System.Threading.CancellationToken)":
|
||||||
|
"self.native_get_attachments_by_point(cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByInventoryItem":
|
||||||
|
"self.native_get_attachments_by_item()",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetAttachmentsByItemId":
|
||||||
|
"self.native_get_attachments_by_id()",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetCurrentOutfitFolderAsync(System.Threading.CancellationToken)":
|
||||||
|
"self.native_get_current_outfit_folder(cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetFolderWearablesAsync(LibreMetaverse.UUID,System.Threading.CancellationToken)":
|
||||||
|
"self.native_get_folder_wearables(folder, cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetWearableAssets(LibreMetaverse.WearableType)":
|
||||||
|
"self.native_get_wearable_assets(type_)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetWearables":
|
||||||
|
"self.native_get_wearables()",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.GetWearablesByType":
|
||||||
|
"self.native_get_wearables_by_type()",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.InventoryItem)":
|
||||||
|
"self.native_is_item_worn(item.base.uuid())",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.IsItemWorn(LibreMetaverse.UUID)":
|
||||||
|
"Ok(self.native_is_item_worn(item_id)? != libremetaverse_types::WearableType::Invalid)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.RemoveFromOutfit(LibreMetaverse.InventoryItem)":
|
||||||
|
"self.native_remove_from_outfit(vec![wearable_item])",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.RemoveFromOutfit(System.Collections.Generic.List{LibreMetaverse.InventoryItem})":
|
||||||
|
"self.native_remove_from_outfit(wearable_items)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem})":
|
||||||
|
"self.native_replace_outfit(wearable_items, false).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.ReplaceOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryItem},System.Boolean)":
|
||||||
|
"self.native_replace_outfit(wearable_items, safe).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.RequestAgentWornAsync(System.Threading.CancellationToken)":
|
||||||
|
"self.native_request_agent_worn(cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.SendOutfitToCurrentSimulatorAsync(System.Threading.CancellationToken)":
|
||||||
|
"self.native_send_outfit(cancellation_token).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.UpdateLastReceivedCOFVersion(System.Int32)":
|
||||||
|
"self.native_update_cof_version(cof_version)",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.WearOutfitAsync(System.Collections.Generic.List{LibreMetaverse.InventoryBase},System.Boolean)":
|
||||||
|
"self.native_wear_outfit(wearables, replace_items).await",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.WearableTypeToAssetType(LibreMetaverse.WearableType)":
|
||||||
|
"Ok(crate::appearance_manager::wearable_type_to_asset_type(type_))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.InventoryItem)":
|
||||||
|
"Ok(self.native_is_item_attached(item.base.uuid()))",
|
||||||
|
"M:LibreMetaverse.AppearanceManager.isItemAttached(LibreMetaverse.UUID)":
|
||||||
|
"Ok(self.native_is_item_attached(key))",
|
||||||
|
"P:LibreMetaverse.AppearanceManager.LastUpdateReceivedCOFVersion":
|
||||||
|
"self.native_last_cof_version()",
|
||||||
|
"P:LibreMetaverse.AppearanceManager.ManagerBusy":
|
||||||
|
"self.native_manager_busy()",
|
||||||
|
"P:LibreMetaverse.GridClient.Appearance":
|
||||||
|
"self.native_appearance().unwrap_or_else(|_| panic!(\"failed to construct AppearanceManager\"))",
|
||||||
|
"P:LibreMetaverse.GridClient.Appearance#set":
|
||||||
|
"self.native_set_appearance(value)",
|
||||||
"M:LibreMetaverse.Avatar.AvatarProperties.FromOSD(LibreMetaverse.StructuredData.OSD)":
|
"M:LibreMetaverse.Avatar.AvatarProperties.FromOSD(LibreMetaverse.StructuredData.OSD)":
|
||||||
"crate::agent_messages::avatar_properties_from_osd(o)",
|
"crate::agent_messages::avatar_properties_from_osd(o)",
|
||||||
"M:LibreMetaverse.Avatar.AvatarProperties.GetOSD":
|
"M:LibreMetaverse.Avatar.AvatarProperties.GetOSD":
|
||||||
@@ -1892,6 +2035,7 @@ PRIVATE_LAYOUTS = {
|
|||||||
}
|
}
|
||||||
VALUE_DERIVES = {
|
VALUE_DERIVES = {
|
||||||
"T:LibreMetaverse.AgentSettings": "Clone, Debug, Eq, PartialEq",
|
"T:LibreMetaverse.AgentSettings": "Clone, Debug, Eq, PartialEq",
|
||||||
|
"T:LibreMetaverse.AppearanceManager.WearableData": "Clone, Debug",
|
||||||
"T:LibreMetaverse.AssetCacheSettings": "Clone, Debug, Eq, PartialEq",
|
"T:LibreMetaverse.AssetCacheSettings": "Clone, Debug, Eq, PartialEq",
|
||||||
"T:LibreMetaverse.BuddyListEntry": "Clone, Debug, Eq, PartialEq",
|
"T:LibreMetaverse.BuddyListEntry": "Clone, Debug, Eq, PartialEq",
|
||||||
"T:LibreMetaverse.ConnectionSettings": "Clone, Eq, PartialEq",
|
"T:LibreMetaverse.ConnectionSettings": "Clone, Eq, PartialEq",
|
||||||
@@ -2390,6 +2534,8 @@ def render_type(item: dict, type_row: dict, member_rows: dict[str, dict[str, str
|
|||||||
# of receiving an invalid empty generated impl.
|
# of receiving an invalid empty generated impl.
|
||||||
if f"T:{base}" in NATIVE_TYPES:
|
if f"T:{base}" in NATIVE_TYPES:
|
||||||
continue
|
continue
|
||||||
|
if item["doc_id"] in NATIVE_DECLARATIONS:
|
||||||
|
continue
|
||||||
if item["doc_id"] == "T:LibreMetaverse.GridClient" and base == "LibreMetaverse.IGridClient":
|
if item["doc_id"] == "T:LibreMetaverse.GridClient" and base == "LibreMetaverse.IGridClient":
|
||||||
continue
|
continue
|
||||||
mapped_arguments = [mapper.type(argument, None, set(names)) for argument in arguments]
|
mapped_arguments = [mapper.type(argument, None, set(names)) for argument in arguments]
|
||||||
|
|||||||
@@ -989,6 +989,7 @@ def validate_generated_shims() -> None:
|
|||||||
"crate::asset_manager::",
|
"crate::asset_manager::",
|
||||||
"crate::asset_material::",
|
"crate::asset_material::",
|
||||||
"crate::asset_models::",
|
"crate::asset_models::",
|
||||||
|
"crate::appearance_manager::",
|
||||||
"crate::byte_order::",
|
"crate::byte_order::",
|
||||||
"crate::attention_catalog::",
|
"crate::attention_catalog::",
|
||||||
"crate::binary::",
|
"crate::binary::",
|
||||||
@@ -1000,8 +1001,10 @@ def validate_generated_shims() -> None:
|
|||||||
"crate::inventory::",
|
"crate::inventory::",
|
||||||
"crate::inventory_ais::",
|
"crate::inventory_ais::",
|
||||||
"crate::inventory_manager::",
|
"crate::inventory_manager::",
|
||||||
|
"crate::current_outfit::",
|
||||||
"crate::message_codec::",
|
"crate::message_codec::",
|
||||||
"crate::message_decoder::",
|
"crate::message_decoder::",
|
||||||
|
"crate::NameValue {",
|
||||||
"crate::object_material::",
|
"crate::object_material::",
|
||||||
"crate::notation::",
|
"crate::notation::",
|
||||||
"crate::packet_catalog::",
|
"crate::packet_catalog::",
|
||||||
@@ -1020,8 +1023,16 @@ def validate_generated_shims() -> None:
|
|||||||
if uses_standardized_or_native_path:
|
if uses_standardized_or_native_path:
|
||||||
continue
|
continue
|
||||||
if FAKE_BODY.search(body):
|
if FAKE_BODY.search(body):
|
||||||
raise ValueError(f"generated shim returns a plausible fallback: {path.relative_to(ROOT)}")
|
excerpt = " ".join(body.strip().split())[:160]
|
||||||
raise ValueError(f"generated shim function does not use the standardized failure: {path.relative_to(ROOT)}")
|
raise ValueError(
|
||||||
|
"generated shim returns a plausible fallback: "
|
||||||
|
f"{path.relative_to(ROOT)}: {excerpt}"
|
||||||
|
)
|
||||||
|
excerpt = " ".join(body.strip().split())[:160]
|
||||||
|
raise ValueError(
|
||||||
|
"generated shim function does not use the standardized failure: "
|
||||||
|
f"{path.relative_to(ROOT)}: {excerpt}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def build_type_rows(catalog: dict) -> tuple[list[dict[str, str]], dict[str, str]]:
|
def build_type_rows(catalog: dict) -> tuple[list[dict[str, str]], dict[str, str]]:
|
||||||
|
|||||||
Reference in New Issue
Block a user