Implement native asset pipeline and cache (#64)
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
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
This commit is contained in:
192
crates/libremetaverse/src/object_material.rs
Normal file
192
crates/libremetaverse/src/object_material.rs
Normal file
@@ -0,0 +1,192 @@
|
||||
//! `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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user