Files
MetaCrate/crates/libremetaverse/src/object_material.rs
Chili Palmer 52f62d8c39
Some checks failed
Native code generation / deterministic (push) Failing after 2m18s
Imaging and meshing gate / native (push) Failing after 1m30s
JPEG 2000 feature / linux (push) Successful in 2m40s
Native Rust workspace compile / compile (push) Failing after 57s
Skia feature / linux (push) Successful in 31m8s
Implement native asset pipeline and cache (#64)
2026-08-10 07:51:17 +00:00

193 lines
6.1 KiB
Rust

//! `ModifyMaterialParams` capability integration.
#![allow(
clippy::missing_errors_doc,
clippy::must_use_candidate,
clippy::option_option
)]
use crate::assets::AssetMaterial;
use crate::{Error, GridClient, Simulator};
use libremetaverse_structured_data::{OSD, OSDParser};
use libremetaverse_types::{UUID, compat::CancellationToken};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Clone, Debug)]
pub struct GLTFMaterialUpdate {
asset_id: Option<Option<UUID>>,
object_id: UUID,
override_: Option<AssetMaterial>,
side: i32,
}
impl GLTFMaterialUpdate {
pub fn new() -> Result<Self, Error> {
Ok(Self {
asset_id: None,
object_id: UUID::zero(),
override_: None,
side: 0,
})
}
pub fn asset_id(&self) -> Option<Option<UUID>> {
self.asset_id
}
pub fn set_asset_id(&mut self, value: Option<Option<UUID>>) {
self.asset_id = value;
}
pub const fn object_id(&self) -> UUID {
self.object_id
}
pub fn set_object_id(&mut self, value: UUID) {
self.object_id = value;
}
pub fn override_(&self) -> Option<AssetMaterial> {
self.override_.clone()
}
pub fn set_override_(&mut self, value: Option<AssetMaterial>) {
self.override_ = value;
}
pub const fn side(&self) -> i32 {
self.side
}
pub fn set_side(&mut self, value: i32) {
self.side = value;
}
}
pub struct ObjectManager {
client: crate::client_core::ClientWeakHandle,
}
impl ObjectManager {
pub(crate) fn native_new(client: Option<Arc<GridClient>>) -> Result<Self, Error> {
Ok(Self {
client: client.ok_or(Error::ArgumentNull)?.native_weak_handle(),
})
}
fn client(&self) -> Result<GridClient, Error> {
self.client.upgrade().ok_or(Error::InvalidOperation)
}
pub(crate) async fn native_send_material_updates(
&self,
sim: Simulator,
updates: Box<dyn Iterator<Item = GLTFMaterialUpdate>>,
cancellation_token: Option<CancellationToken>,
) -> Result<bool, Error> {
let Some(caps) = sim.native_caps() else {
return Ok(false);
};
let deadline = Instant::now() + Duration::from_secs(2);
let uri = loop {
if let Some(uri) = caps.capability_uri("ModifyMaterialParams".into())? {
break uri;
}
if caps.seed_request_finished() || Instant::now() >= deadline {
return Ok(false);
}
std::thread::sleep(Duration::from_millis(1));
};
let mut body = Vec::new();
for update in updates {
if update.side < 0 {
return Err(Error::Argument);
}
let mut entry = HashMap::from([
("object_id".into(), OSD::UUID(update.object_id)),
("side".into(), OSD::Integer(update.side)),
]);
if let Some(Some(asset_id)) = update.asset_id {
entry.insert("asset_id".into(), OSD::UUID(asset_id));
}
if let Some(material) = update.override_ {
entry.insert("gltf_json".into(), OSD::String(material.to_json()?));
} else if update.asset_id.flatten().is_none() {
entry.insert("gltf_json".into(), OSD::String(String::new()));
}
body.push(OSD::Map(entry));
}
if body.is_empty() {
return Err(Error::Argument);
}
let payload = OSDParser::serialize_llsd_xml_bytes(OSD::Array(body))?;
let client = self.client()?;
let (response, bytes) = client
.native_http_caps_client()
.post_with_uri_string_bytes_cancellation_token_i_progress(
uri,
"application/llsd+xml".into(),
payload,
cancellation_token.unwrap_or_default(),
None,
)
.await?;
if !(200..300).contains(&response.status_code) {
return Ok(false);
}
let response: serde_json::Value =
serde_json::from_slice(&bytes).map_err(|_| Error::Argument)?;
Ok(response
.get("success")
.and_then(serde_json::Value::as_bool)
.unwrap_or(false))
}
pub(crate) async fn native_set_material_override(
&self,
sim: Simulator,
object_id: UUID,
side: i32,
override_material: AssetMaterial,
cancellation_token: Option<CancellationToken>,
) -> Result<bool, Error> {
let mut update = GLTFMaterialUpdate::new()?;
update.object_id = object_id;
update.side = side;
update.override_ = Some(override_material);
self.native_send_material_updates(
sim,
Box::new(std::iter::once(update)),
cancellation_token,
)
.await
}
pub(crate) async fn native_clear_material_override(
&self,
sim: Simulator,
object_id: UUID,
side: i32,
cancellation_token: Option<CancellationToken>,
) -> Result<bool, Error> {
let mut update = GLTFMaterialUpdate::new()?;
update.object_id = object_id;
update.side = side;
self.native_send_material_updates(
sim,
Box::new(std::iter::once(update)),
cancellation_token,
)
.await
}
pub(crate) async fn native_apply_material(
&self,
sim: Simulator,
object_id: UUID,
side: i32,
material_asset_id: UUID,
override_material: Option<AssetMaterial>,
cancellation_token: Option<CancellationToken>,
) -> Result<bool, Error> {
let mut update = GLTFMaterialUpdate::new()?;
update.object_id = object_id;
update.side = side;
update.asset_id = Some(Some(material_asset_id));
update.override_ = override_material;
self.native_send_material_updates(
sim,
Box::new(std::iter::once(update)),
cancellation_token,
)
.await
}
}