Complete first release candidate audit (#107)
Some checks failed
API and SemVer surface / api-surface (push) Failing after 1m34s
Native code generation / deterministic (push) Has been cancelled
Concurrency and resource soak audit / soak (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
performance evidence / audit (push) Has been cancelled
First release candidate / non-fuzz-release-gate (push) Has been cancelled
Release platform and feature matrix / audit (push) Has been cancelled
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Native release artifact audit / audit (push) Has been cancelled
Imaging and meshing gate / native (push) Failing after 53s
JPEG 2000 feature / linux (push) Successful in 2m49s
Native Rust workspace compile / compile (push) Failing after 59s
Skia feature / linux (push) Has been cancelled
Some checks failed
API and SemVer surface / api-surface (push) Failing after 1m34s
Native code generation / deterministic (push) Has been cancelled
Concurrency and resource soak audit / soak (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
performance evidence / audit (push) Has been cancelled
First release candidate / non-fuzz-release-gate (push) Has been cancelled
Release platform and feature matrix / audit (push) Has been cancelled
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Native release artifact audit / audit (push) Has been cancelled
Imaging and meshing gate / native (push) Failing after 53s
JPEG 2000 feature / linux (push) Successful in 2m49s
Native Rust workspace compile / compile (push) Failing after 59s
Skia feature / linux (push) Has been cancelled
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
//! Native LLSD field codecs for the translated Linden message fixtures.
|
||||
|
||||
#![allow(clippy::cast_possible_truncation)] // LLSD reals intentionally narrow to wire f32 fields.
|
||||
#![allow(clippy::too_many_arguments)] // Codec helpers mirror fixed message field sets.
|
||||
#![allow(clippy::type_complexity)] // Parsed tuples preserve the mapped message shape.
|
||||
#![allow(clippy::unnecessary_wraps)] // Handlers share the fallible registry signature.
|
||||
|
||||
use crate::messages::linden::{
|
||||
AgentDropGroupMessage, AgentDropGroupMessageAgentData, AgentGroupDataUpdateMessage,
|
||||
AgentGroupDataUpdateMessageGroupData, AgentGroupDataUpdateMessageNewGroupData,
|
||||
AgentStateUpdateMessage, BulkUpdateInventoryMessage, BulkUpdateInventoryMessageFolderDataInfo,
|
||||
BulkUpdateInventoryMessageItemDataInfo, ChatSessionAcceptInvitation, ChatSessionRequestBlock,
|
||||
ChatSessionRequestMuteUpdate, ChatSessionRequestStartConference, ChatterBoxInvitationMessage,
|
||||
AgentStateUpdateMessage, BaseResourcesInfo, BulkUpdateInventoryMessage,
|
||||
BulkUpdateInventoryMessageFolderDataInfo, BulkUpdateInventoryMessageItemDataInfo,
|
||||
ChatSessionAcceptInvitation, ChatSessionRequestMessage, ChatSessionRequestMuteUpdate,
|
||||
ChatSessionRequestStartConference, ChatterBoxInvitationMessage,
|
||||
ChatterBoxSessionAgentListUpdatesMessage,
|
||||
ChatterBoxSessionAgentListUpdatesMessageAgentUpdatesBlock, ChatterBoxSessionStartReplyMessage,
|
||||
ChatterboxSessionEventReplyMessage, CopyInventoryFromNotecardMessage, CrossedRegionMessage,
|
||||
@@ -13,20 +19,29 @@ use crate::messages::linden::{
|
||||
EnableSimulatorMessage, EnableSimulatorMessageSimulatorInfoBlock,
|
||||
EstablishAgentCommunicationMessage, ForceCloseChatterBoxSessionMessage, GetDisplayNamesMessage,
|
||||
GetObjectCostMessage, GetObjectCostRequest, LandResourcesMessage, LandResourcesRequest,
|
||||
LandStatReplyMessage, LandStatReplyMessageReportDataBlock, MapLayerMessageBase,
|
||||
LandStatReplyMessage, LandStatReplyMessageReportDataBlock, MapLayerMessage,
|
||||
MapLayerReplyVariant, MapLayerReplyVariantLayerData, NavMeshStatusUpdateMessage,
|
||||
ObjectMediaNavigateMessage, ObjectMediaRequest, ObjectMediaResponse, ObjectMediaUpdate,
|
||||
ObjectPhysicsPropertiesMessage, ParcelObjectOwnersReplyMessage,
|
||||
ParcelObjectOwnersReplyMessagePrimOwner, ParcelPropertiesMessage,
|
||||
ParcelPropertiesUpdateMessage, ParcelVoiceInfoRequestMessage, PlacesReplyMessage,
|
||||
PlacesReplyMessageQueryData, ProvisionVoiceAccountRequestMessage, RegionInfoMessage,
|
||||
RemoteParcelRequestReply, RenderMaterialsMessage, RequiredVoiceVersionMessage,
|
||||
ScriptRunningReplyMessage, SearchStatRequestReply, SearchStatRequestRequest,
|
||||
SendPostcardMessage, SetDisplayNameMessage, SetDisplayNameReplyMessage,
|
||||
SimConsoleResponseMessage, TeleportFailedMessage, TeleportFinishMessage,
|
||||
UpdateAgentInformationMessage, UpdateAgentInventoryRequestMessage, UpdateAgentLanguageMessage,
|
||||
UpdateScriptAgentRequestMessage, UpdateScriptTaskUpdateMessage, UploaderRequestComplete,
|
||||
UploaderRequestUpload, ViewerStatsMessage,
|
||||
NewFileAgentInventoryMessage, NewFileAgentInventoryReplyMessage,
|
||||
NewFileAgentInventoryUploadReplyMessage, NewFileAgentInventoryVariablePriceMessage,
|
||||
NewFileAgentInventoryVariablePriceReplyMessage, ObjectMediaMessage, ObjectMediaNavigateMessage,
|
||||
ObjectMediaRequest, ObjectMediaResponse, ObjectMediaUpdate, ObjectPhysicsPropertiesMessage,
|
||||
ParcelObjectOwnersReplyMessage, ParcelObjectOwnersReplyMessagePrimOwner,
|
||||
ParcelPropertiesMessage, ParcelPropertiesUpdateMessage, ParcelVoiceInfoRequestMessage,
|
||||
PlacesReplyMessage, PlacesReplyMessageQueryData, ProvisionVoiceAccountRequestMessage,
|
||||
RegionInfoMessage, RemoteParcelRequestMessage, RemoteParcelRequestReply,
|
||||
RemoteParcelRequestRequest, RenderMaterialsMessage, RequiredVoiceVersionMessage,
|
||||
ScriptRunningReplyMessage, SearchStatRequestMessage, SearchStatRequestReply,
|
||||
SearchStatRequestRequest, SendPostcardMessage, SetDisplayNameMessage,
|
||||
SetDisplayNameReplyMessage, SimConsoleResponseMessage, TeleportFailedMessage,
|
||||
TeleportFinishMessage, UpdateAgentInformationMessage, UpdateAgentInventoryRequestMessage,
|
||||
UpdateAgentLanguageMessage, UpdateGestureAgentInventoryMessage,
|
||||
UpdateNotecardAgentInventoryMessage, UpdateNotecardTaskInventoryMessage,
|
||||
UpdateScriptAgentMessage, UpdateScriptAgentRequestMessage, UpdateScriptTaskMessage,
|
||||
UpdateScriptTaskUpdateMessage, UploadBakedTextureMessage, UploadObjectAssetMessage,
|
||||
UploadObjectAssetMessageObject, UploadObjectAssetMessageObjectExtraParam,
|
||||
UploadObjectAssetMessageObjectFace, UploadScriptTaskMessage, UploaderRequestComplete,
|
||||
UploaderRequestScriptComplete, UploaderRequestUpload, UploaderScriptRequestError,
|
||||
ViewerStatsMessage,
|
||||
};
|
||||
use crate::{
|
||||
AgentDisplayName, Error, GroupPowers, InstantMessageDialog, InstantMessageOnline, LandingType,
|
||||
@@ -36,7 +51,10 @@ use crate::{
|
||||
use flate2::read::ZlibDecoder;
|
||||
use libremetaverse_structured_data::{OSD, OSDMap, OSDParser};
|
||||
use libremetaverse_types::compat::Uri;
|
||||
use libremetaverse_types::{AssetType, FolderType, InventoryType, SaleType, UUID, Vector3};
|
||||
use libremetaverse_types::{
|
||||
AssetType, Color4, ExtraParamType, FolderType, InventoryType, Material, Quaternion, SaleType,
|
||||
SculptType, UUID, Vector3,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::io::Read as _;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
@@ -54,6 +72,38 @@ pub(crate) trait GeneratedMessage: Sized {
|
||||
fn deserialize_generated(&mut self, map: &OSDMap) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub(crate) fn generated_from_osd<T: GeneratedMessage>(data: OSD) -> Result<T, Error> {
|
||||
let OSD::Map(values) = data else {
|
||||
return Err(Error::Argument);
|
||||
};
|
||||
let map = OSDMap::new_with_dictionary(values)?;
|
||||
let mut value = T::new_generated();
|
||||
value.deserialize_generated(&map)?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub(crate) fn get_object_cost_handler(
|
||||
map: &OSDMap,
|
||||
) -> Result<Option<Box<dyn crate::interfaces::IMessage>>, Error> {
|
||||
if map.get("object_ids").is_some() {
|
||||
Ok(Some(Box::new(GetObjectCostRequest::new_generated())))
|
||||
} else {
|
||||
Ok(Some(Box::new(GetObjectCostMessage::new_generated())))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn land_resources_handler(
|
||||
map: &OSDMap,
|
||||
) -> Result<Option<Box<dyn crate::interfaces::IMessage>>, Error> {
|
||||
if map.get("parcel_id").is_some() {
|
||||
Ok(Some(Box::new(LandResourcesRequest::new_generated())))
|
||||
} else if map.get("ScriptResourceSummary").is_some() {
|
||||
Ok(Some(Box::new(LandResourcesMessage::new_generated())))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! integer_value {
|
||||
($type:ty, $from:ident, $as:ident) => {
|
||||
impl MessageValue for $type {
|
||||
@@ -232,6 +282,24 @@ impl MessageValue for OSDMap {
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageValue for HashMap<String, i32> {
|
||||
fn message_default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
fn to_message_osd(&self) -> Result<OSD, Error> {
|
||||
self.iter()
|
||||
.map(|(key, value)| Ok((key.clone(), value.to_message_osd()?)))
|
||||
.collect::<Result<HashMap<_, _>, Error>>()
|
||||
.map(OSD::Map)
|
||||
}
|
||||
fn from_message_osd(value: &OSD) -> Result<Self, Error> {
|
||||
as_map(value)?
|
||||
.iter()
|
||||
.map(|(key, value)| Ok((key.clone(), i32::from_message_osd(value)?)))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageValue for AgentDisplayName {
|
||||
fn message_default() -> Self {
|
||||
Self::new().expect("AgentDisplayName construction is infallible")
|
||||
@@ -813,6 +881,50 @@ fn deserialize_get_object_cost(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_base_resources(value: &BaseResourcesInfo) -> Result<OSDMap, Error> {
|
||||
fn entries(values: &HashMap<String, i32>) -> Result<OSD, Error> {
|
||||
let mut values: Vec<_> = values.iter().collect();
|
||||
values.sort_unstable_by(|left, right| left.0.cmp(right.0));
|
||||
values
|
||||
.into_iter()
|
||||
.map(|(type_, amount)| {
|
||||
Ok(map_osd([
|
||||
("type", type_.to_message_osd()?),
|
||||
("amount", amount.to_message_osd()?),
|
||||
]))
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>()
|
||||
.map(OSD::Array)
|
||||
}
|
||||
finish_map([(
|
||||
"summary",
|
||||
map_osd([
|
||||
("available", entries(&value.summary_available)?),
|
||||
("used", entries(&value.summary_used)?),
|
||||
]),
|
||||
)])
|
||||
}
|
||||
|
||||
fn deserialize_base_resources(value: &mut BaseResourcesInfo, map: &OSDMap) -> Result<(), Error> {
|
||||
fn entries(value: &OSD) -> Result<HashMap<String, i32>, Error> {
|
||||
as_array(value)?
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
let entry = as_map(entry)?;
|
||||
Ok((
|
||||
String::from_message_osd(required_from(entry, "type")?)?,
|
||||
i32::from_message_osd(required_from(entry, "amount")?)?,
|
||||
))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
let summary_value = required(map, "summary")?;
|
||||
let summary = as_map(&summary_value)?;
|
||||
value.summary_available = entries(required_from(summary, "available")?)?;
|
||||
value.summary_used = entries(required_from(summary, "used")?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_nav_mesh_status(value: &NavMeshStatusUpdateMessage) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
("region_id", value.region_id.to_message_osd()?),
|
||||
@@ -1172,6 +1284,50 @@ macro_rules! custom_message {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wrapped_message {
|
||||
($type:ty) => {
|
||||
impl GeneratedMessage for $type {
|
||||
fn new_generated() -> Self {
|
||||
Self {
|
||||
request: MessageValue::message_default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_generated(&self) -> Result<OSDMap, Error> {
|
||||
let OSD::Map(values) = self.request.to_message_osd()? else {
|
||||
return Err(Error::Argument);
|
||||
};
|
||||
OSDMap::new_with_dictionary(values)
|
||||
}
|
||||
|
||||
fn deserialize_generated(&mut self, map: &OSDMap) -> Result<(), Error> {
|
||||
self.request = MessageValue::from_message_osd(&map.copy()?)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageValue for $type {
|
||||
fn message_default() -> Self {
|
||||
<Self as GeneratedMessage>::new_generated()
|
||||
}
|
||||
|
||||
fn to_message_osd(&self) -> Result<OSD, Error> {
|
||||
self.serialize_generated()?.copy()
|
||||
}
|
||||
|
||||
fn from_message_osd(value: &OSD) -> Result<Self, Error> {
|
||||
let OSD::Map(values) = value else {
|
||||
return Err(Error::Argument);
|
||||
};
|
||||
let map = OSDMap::new_with_dictionary(values.clone())?;
|
||||
let mut output = <Self as GeneratedMessage>::new_generated();
|
||||
output.deserialize_generated(&map)?;
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! osd_entries {
|
||||
($value:expr; $($field:ident => $key:literal),* $(,)?) => {
|
||||
vec![$(($key, $value.$field.to_message_osd()?)),*]
|
||||
@@ -1237,11 +1393,6 @@ custom_message!(AgentGroupDataUpdateMessage {
|
||||
array: [group_data_block, new_group_data_block],
|
||||
bytes: []
|
||||
} => serialize_agent_group, deserialize_agent_group);
|
||||
map_message!(ChatSessionRequestBlock {
|
||||
scalar: [method => "method"],
|
||||
array: [],
|
||||
bytes: []
|
||||
});
|
||||
custom_message!(ChatSessionAcceptInvitation { scalar: [base, session_id], array: [], bytes: [] } => serialize_chat_accept, deserialize_chat_accept, init |value: &mut ChatSessionAcceptInvitation| value.base.method = "accept invitation".into());
|
||||
custom_message!(ChatSessionRequestMuteUpdate { scalar: [base, agent_id, request_key, request_value, session_id], array: [], bytes: [] } => serialize_chat_mute, deserialize_chat_mute, init |value: &mut ChatSessionRequestMuteUpdate| value.base.method = "mute update".into());
|
||||
custom_message!(ChatSessionRequestStartConference { scalar: [base, session_id], array: [agents_block], bytes: [] } => serialize_chat_start, deserialize_chat_start, init |value: &mut ChatSessionRequestStartConference| value.base.method = "start conference".into());
|
||||
@@ -1372,11 +1523,6 @@ custom_message!(LandStatReplyMessage {
|
||||
array: [report_data_blocks],
|
||||
bytes: []
|
||||
} => serialize_land_stat, deserialize_land_stat);
|
||||
map_message!(MapLayerMessageBase {
|
||||
scalar: [flags => "Flags"],
|
||||
array: [],
|
||||
bytes: []
|
||||
});
|
||||
map_message!(MapLayerReplyVariantLayerData {
|
||||
scalar: [
|
||||
bottom => "Bottom",
|
||||
@@ -1582,6 +1728,11 @@ custom_message!(GetObjectCostMessage {
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_get_object_cost, deserialize_get_object_cost);
|
||||
custom_message!(BaseResourcesInfo {
|
||||
scalar: [summary_available, summary_used],
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_base_resources, deserialize_base_resources);
|
||||
map_message!(GetObjectCostRequest {
|
||||
scalar: [],
|
||||
array: [object_i_ds => "object_ids"],
|
||||
@@ -1793,6 +1944,229 @@ custom_message!(UploaderRequestComplete {
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_uploader_complete, deserialize_uploader_complete);
|
||||
custom_message!(NewFileAgentInventoryMessage {
|
||||
scalar: [asset_type, description, everyone_mask, folder_id, group_mask, inventory_type, name, next_owner_mask],
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_new_file_inventory, deserialize_new_file_inventory);
|
||||
custom_message!(NewFileAgentInventoryVariablePriceMessage {
|
||||
scalar: [asset_type, description, everyone_mask, folder_id, group_mask, inventory_type, name, next_owner_mask],
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_new_file_inventory_variable, deserialize_new_file_inventory_variable);
|
||||
map_message!(NewFileAgentInventoryReplyMessage {
|
||||
scalar: [state => "state", uploader => "uploader"],
|
||||
array: [],
|
||||
bytes: []
|
||||
} init |value: &mut NewFileAgentInventoryReplyMessage| value.state = "upload".into());
|
||||
map_message!(NewFileAgentInventoryVariablePriceReplyMessage {
|
||||
scalar: [resource_cost => "resource_cost", rsvp => "rsvp", state => "state", upload_price => "upload_price"],
|
||||
array: [],
|
||||
bytes: []
|
||||
} init |value: &mut NewFileAgentInventoryVariablePriceReplyMessage| value.state = "confirm_upload".into());
|
||||
map_message!(NewFileAgentInventoryUploadReplyMessage {
|
||||
scalar: [
|
||||
new_asset => "new_asset",
|
||||
new_base_mask => "new_base_mask",
|
||||
new_everyone_mask => "new_everyone_mask",
|
||||
new_inventory_item => "new_inventory_item",
|
||||
new_next_owner_mask => "new_next_owner_mask",
|
||||
new_owner_mask => "new_owner_mask",
|
||||
state => "state"
|
||||
],
|
||||
array: [],
|
||||
bytes: []
|
||||
} init |value: &mut NewFileAgentInventoryUploadReplyMessage| value.state = "complete".into());
|
||||
map_message!(UpdateNotecardTaskInventoryMessage {
|
||||
scalar: [item_id => "item_id", task_id => "task_id"],
|
||||
array: [],
|
||||
bytes: []
|
||||
});
|
||||
custom_message!(UploaderRequestScriptComplete {
|
||||
scalar: [asset_id, compiled],
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_uploader_script_complete, deserialize_uploader_script_complete);
|
||||
custom_message!(UploaderScriptRequestError {
|
||||
scalar: [asset_id, compiled, error],
|
||||
array: [],
|
||||
bytes: []
|
||||
} => serialize_uploader_script_error, deserialize_uploader_script_error);
|
||||
map_message!(RemoteParcelRequestRequest {
|
||||
scalar: [location => "location", region_handle => "region_handle", region_id => "region_id"],
|
||||
array: [],
|
||||
bytes: []
|
||||
});
|
||||
wrapped_message!(ChatSessionRequestMessage);
|
||||
wrapped_message!(MapLayerMessage);
|
||||
wrapped_message!(ObjectMediaMessage);
|
||||
wrapped_message!(RemoteParcelRequestMessage);
|
||||
wrapped_message!(SearchStatRequestMessage);
|
||||
wrapped_message!(UpdateGestureAgentInventoryMessage);
|
||||
wrapped_message!(UpdateNotecardAgentInventoryMessage);
|
||||
wrapped_message!(UpdateScriptAgentMessage);
|
||||
wrapped_message!(UpdateScriptTaskMessage);
|
||||
wrapped_message!(UploadBakedTextureMessage);
|
||||
wrapped_message!(UploadScriptTaskMessage);
|
||||
|
||||
fn serialize_new_file_inventory_fields(
|
||||
asset_type: AssetType,
|
||||
description: &str,
|
||||
everyone_mask: PermissionMask,
|
||||
folder_id: UUID,
|
||||
group_mask: PermissionMask,
|
||||
inventory_type: InventoryType,
|
||||
name: &str,
|
||||
next_owner_mask: PermissionMask,
|
||||
) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
("folder_id", folder_id.to_message_osd()?),
|
||||
(
|
||||
"asset_type",
|
||||
libremetaverse_types::Utils::asset_type_to_string(asset_type)?.to_message_osd()?,
|
||||
),
|
||||
(
|
||||
"inventory_type",
|
||||
libremetaverse_types::Utils::inventory_type_to_string(inventory_type)?
|
||||
.to_message_osd()?,
|
||||
),
|
||||
("name", name.to_owned().to_message_osd()?),
|
||||
("description", description.to_owned().to_message_osd()?),
|
||||
("everyone_mask", everyone_mask.to_message_osd()?),
|
||||
("group_mask", group_mask.to_message_osd()?),
|
||||
("next_owner_mask", next_owner_mask.to_message_osd()?),
|
||||
])
|
||||
}
|
||||
|
||||
fn deserialize_new_file_inventory_fields(
|
||||
map: &OSDMap,
|
||||
) -> Result<
|
||||
(
|
||||
AssetType,
|
||||
String,
|
||||
PermissionMask,
|
||||
UUID,
|
||||
PermissionMask,
|
||||
InventoryType,
|
||||
String,
|
||||
PermissionMask,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
Ok((
|
||||
libremetaverse_types::Utils::string_to_asset_type(decode_top(map, "asset_type")?)?,
|
||||
decode_top(map, "description")?,
|
||||
decode_top(map, "everyone_mask")?,
|
||||
decode_top(map, "folder_id")?,
|
||||
decode_top(map, "group_mask")?,
|
||||
libremetaverse_types::Utils::string_to_inventory_type(decode_top(map, "inventory_type")?)?,
|
||||
decode_top(map, "name")?,
|
||||
decode_top(map, "next_owner_mask")?,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_new_file_inventory(value: &NewFileAgentInventoryMessage) -> Result<OSDMap, Error> {
|
||||
serialize_new_file_inventory_fields(
|
||||
value.asset_type,
|
||||
&value.description,
|
||||
value.everyone_mask,
|
||||
value.folder_id,
|
||||
value.group_mask,
|
||||
value.inventory_type,
|
||||
&value.name,
|
||||
value.next_owner_mask,
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_new_file_inventory(
|
||||
value: &mut NewFileAgentInventoryMessage,
|
||||
map: &OSDMap,
|
||||
) -> Result<(), Error> {
|
||||
(
|
||||
value.asset_type,
|
||||
value.description,
|
||||
value.everyone_mask,
|
||||
value.folder_id,
|
||||
value.group_mask,
|
||||
value.inventory_type,
|
||||
value.name,
|
||||
value.next_owner_mask,
|
||||
) = deserialize_new_file_inventory_fields(map)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_new_file_inventory_variable(
|
||||
value: &NewFileAgentInventoryVariablePriceMessage,
|
||||
) -> Result<OSDMap, Error> {
|
||||
serialize_new_file_inventory_fields(
|
||||
value.asset_type,
|
||||
&value.description,
|
||||
value.everyone_mask,
|
||||
value.folder_id,
|
||||
value.group_mask,
|
||||
value.inventory_type,
|
||||
&value.name,
|
||||
value.next_owner_mask,
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_new_file_inventory_variable(
|
||||
value: &mut NewFileAgentInventoryVariablePriceMessage,
|
||||
map: &OSDMap,
|
||||
) -> Result<(), Error> {
|
||||
(
|
||||
value.asset_type,
|
||||
value.description,
|
||||
value.everyone_mask,
|
||||
value.folder_id,
|
||||
value.group_mask,
|
||||
value.inventory_type,
|
||||
value.name,
|
||||
value.next_owner_mask,
|
||||
) = deserialize_new_file_inventory_fields(map)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_uploader_script_complete(
|
||||
value: &UploaderRequestScriptComplete,
|
||||
) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
("state", "complete".to_owned().to_message_osd()?),
|
||||
("new_asset", value.asset_id.to_message_osd()?),
|
||||
("compiled", value.compiled.to_message_osd()?),
|
||||
])
|
||||
}
|
||||
|
||||
fn deserialize_uploader_script_complete(
|
||||
value: &mut UploaderRequestScriptComplete,
|
||||
map: &OSDMap,
|
||||
) -> Result<(), Error> {
|
||||
value.asset_id = decode_top(map, "new_asset")?;
|
||||
value.compiled = decode_top(map, "compiled")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_uploader_script_error(value: &UploaderScriptRequestError) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
("state", "complete".to_owned().to_message_osd()?),
|
||||
("new_asset", value.asset_id.to_message_osd()?),
|
||||
("compiled", value.compiled.to_message_osd()?),
|
||||
("errors", encode_array(std::slice::from_ref(&value.error))?),
|
||||
])
|
||||
}
|
||||
|
||||
fn deserialize_uploader_script_error(
|
||||
value: &mut UploaderScriptRequestError,
|
||||
map: &OSDMap,
|
||||
) -> Result<(), Error> {
|
||||
value.asset_id = decode_top(map, "new_asset")?;
|
||||
value.compiled = decode_top(map, "compiled")?;
|
||||
value.error = decode_array::<String>(&required(map, "errors")?)?
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or(Error::Argument)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_agent_group(value: &AgentGroupDataUpdateMessage) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
@@ -2918,6 +3292,329 @@ fn deserialize_viewer_stats(value: &mut ViewerStatsMessage, map: &OSDMap) -> Res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn material_from_i32(value: i32) -> Result<Material, Error> {
|
||||
match value {
|
||||
0 => Ok(Material::Stone),
|
||||
1 => Ok(Material::Metal),
|
||||
2 => Ok(Material::Glass),
|
||||
3 => Ok(Material::Wood),
|
||||
4 => Ok(Material::Flesh),
|
||||
5 => Ok(Material::Plastic),
|
||||
6 => Ok(Material::Rubber),
|
||||
7 => Ok(Material::Light),
|
||||
_ => Err(Error::Argument),
|
||||
}
|
||||
}
|
||||
|
||||
fn sculpt_type_from_i32(value: i32) -> Result<SculptType, Error> {
|
||||
match value {
|
||||
0 => Ok(SculptType::None),
|
||||
1 => Ok(SculptType::Sphere),
|
||||
2 => Ok(SculptType::Torus),
|
||||
3 => Ok(SculptType::Plane),
|
||||
4 => Ok(SculptType::Cylinder),
|
||||
5 => Ok(SculptType::Mesh),
|
||||
64 => Ok(SculptType::Invert),
|
||||
128 => Ok(SculptType::Mirror),
|
||||
_ => Err(Error::Argument),
|
||||
}
|
||||
}
|
||||
|
||||
fn bumpiness_from_i32(value: i32) -> Result<crate::Bumpiness, Error> {
|
||||
use crate::Bumpiness;
|
||||
match value {
|
||||
0 => Ok(Bumpiness::None),
|
||||
1 => Ok(Bumpiness::Brightness),
|
||||
2 => Ok(Bumpiness::Darkness),
|
||||
3 => Ok(Bumpiness::Woodgrain),
|
||||
4 => Ok(Bumpiness::Bark),
|
||||
5 => Ok(Bumpiness::Bricks),
|
||||
6 => Ok(Bumpiness::Checker),
|
||||
7 => Ok(Bumpiness::Concrete),
|
||||
8 => Ok(Bumpiness::Crustytile),
|
||||
9 => Ok(Bumpiness::Cutstone),
|
||||
10 => Ok(Bumpiness::Discs),
|
||||
11 => Ok(Bumpiness::Gravel),
|
||||
12 => Ok(Bumpiness::Petridish),
|
||||
13 => Ok(Bumpiness::Siding),
|
||||
14 => Ok(Bumpiness::Stonetile),
|
||||
15 => Ok(Bumpiness::Stucco),
|
||||
16 => Ok(Bumpiness::Suction),
|
||||
17 => Ok(Bumpiness::Weave),
|
||||
_ => Err(Error::Argument),
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneratedMessage for UploadObjectAssetMessageObjectFace {
|
||||
fn new_generated() -> Self {
|
||||
Self {
|
||||
bump: crate::Bumpiness::None,
|
||||
color: Color4::default(),
|
||||
fullbright: false,
|
||||
glow: 0.0,
|
||||
image_id: UUID::zero(),
|
||||
image_rot: 0.0,
|
||||
media_flags: 0,
|
||||
offset_s: 0.0,
|
||||
offset_t: 0.0,
|
||||
scale_s: 0.0,
|
||||
scale_t: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_generated(&self) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
("bump", OSD::Integer(self.bump as i32)),
|
||||
("colors", OSD::from_color4(self.color)?),
|
||||
("fullbright", OSD::Boolean(self.fullbright)),
|
||||
("glow", OSD::Real(f64::from(self.glow))),
|
||||
("imageid", OSD::UUID(self.image_id)),
|
||||
("imagerot", OSD::Real(f64::from(self.image_rot))),
|
||||
("media_flags", OSD::Integer(self.media_flags)),
|
||||
("offsets", OSD::Real(f64::from(self.offset_s))),
|
||||
("offsett", OSD::Real(f64::from(self.offset_t))),
|
||||
("scales", OSD::Real(f64::from(self.scale_s))),
|
||||
("scalet", OSD::Real(f64::from(self.scale_t))),
|
||||
])
|
||||
}
|
||||
|
||||
fn deserialize_generated(&mut self, map: &OSDMap) -> Result<(), Error> {
|
||||
self.bump = bumpiness_from_i32(required(map, "bump")?.as_integer()?)?;
|
||||
self.color = required(map, "colors")?.as_color4()?;
|
||||
self.fullbright = required(map, "fullbright")?.as_boolean()?;
|
||||
self.glow = required(map, "glow")?.as_real()? as f32;
|
||||
self.image_id = required(map, "imageid")?.as_uuid()?;
|
||||
self.image_rot = required(map, "imagerot")?.as_real()? as f32;
|
||||
self.media_flags = required(map, "media_flags")?.as_integer()?;
|
||||
self.offset_s = required(map, "offsets")?.as_real()? as f32;
|
||||
self.offset_t = required(map, "offsett")?.as_real()? as f32;
|
||||
self.scale_s = required(map, "scales")?.as_real()? as f32;
|
||||
self.scale_t = required(map, "scalet")?.as_real()? as f32;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneratedMessage for UploadObjectAssetMessageObjectExtraParam {
|
||||
fn new_generated() -> Self {
|
||||
Self {
|
||||
extra_param_data: Vec::new(),
|
||||
type_: ExtraParamType(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_generated(&self) -> Result<OSDMap, Error> {
|
||||
finish_map([
|
||||
("extra_parameter", OSD::Integer(i32::from(self.type_.0))),
|
||||
("param_data", OSD::Binary(self.extra_param_data.clone())),
|
||||
])
|
||||
}
|
||||
|
||||
fn deserialize_generated(&mut self, map: &OSDMap) -> Result<(), Error> {
|
||||
self.type_ = ExtraParamType(
|
||||
u16::try_from(required(map, "extra_parameter")?.as_integer()?)
|
||||
.map_err(|_| Error::Argument)?,
|
||||
);
|
||||
self.extra_param_data = required(map, "param_data")?.as_binary()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn upload_object_default() -> UploadObjectAssetMessageObject {
|
||||
UploadObjectAssetMessageObject {
|
||||
extra_params: Vec::new(),
|
||||
faces: Vec::new(),
|
||||
group_id: UUID::zero(),
|
||||
material: Material::Stone,
|
||||
name: String::new(),
|
||||
path_begin: 0.0,
|
||||
path_curve: 0,
|
||||
path_end: 0.0,
|
||||
position: Vector3::zero(),
|
||||
profile_begin: 0.0,
|
||||
profile_curve: 0,
|
||||
profile_end: 0.0,
|
||||
profile_hollow: 0.0,
|
||||
radius_offset: 0.0,
|
||||
revolutions: 0.0,
|
||||
rotation: Quaternion::identity(),
|
||||
scale: Vector3::zero(),
|
||||
scale_x: 0.0,
|
||||
scale_y: 0.0,
|
||||
sculpt_id: UUID::zero(),
|
||||
sculpt_type: SculptType::None,
|
||||
shear_x: 0.0,
|
||||
shear_y: 0.0,
|
||||
skew: 0.0,
|
||||
taper_x: 0.0,
|
||||
taper_y: 0.0,
|
||||
twist: 0.0,
|
||||
twist_begin: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneratedMessage for UploadObjectAssetMessageObject {
|
||||
fn new_generated() -> Self {
|
||||
upload_object_default()
|
||||
}
|
||||
|
||||
fn serialize_generated(&self) -> Result<OSDMap, Error> {
|
||||
let encode = |values: &[&dyn GeneratedMessageObject]| -> Result<OSD, Error> {
|
||||
Ok(OSD::Array(
|
||||
values
|
||||
.iter()
|
||||
.map(|value| value.encode())
|
||||
.collect::<Result<_, _>>()?,
|
||||
))
|
||||
};
|
||||
let extras: Vec<&dyn GeneratedMessageObject> =
|
||||
self.extra_params.iter().map(|v| v as _).collect();
|
||||
let faces: Vec<&dyn GeneratedMessageObject> = self.faces.iter().map(|v| v as _).collect();
|
||||
let shape = map_osd([
|
||||
(
|
||||
"path",
|
||||
map_osd([
|
||||
("begin", OSD::Real(f64::from(self.path_begin))),
|
||||
("curve", OSD::Integer(self.path_curve)),
|
||||
("end", OSD::Real(f64::from(self.path_end))),
|
||||
("radius_offset", OSD::Real(f64::from(self.radius_offset))),
|
||||
("revolutions", OSD::Real(f64::from(self.revolutions))),
|
||||
("scale_x", OSD::Real(f64::from(self.scale_x))),
|
||||
("scale_y", OSD::Real(f64::from(self.scale_y))),
|
||||
("shear_x", OSD::Real(f64::from(self.shear_x))),
|
||||
("shear_y", OSD::Real(f64::from(self.shear_y))),
|
||||
("skew", OSD::Real(f64::from(self.skew))),
|
||||
("taper_x", OSD::Real(f64::from(self.taper_x))),
|
||||
("taper_y", OSD::Real(f64::from(self.taper_y))),
|
||||
("twist", OSD::Real(f64::from(self.twist))),
|
||||
("twist_begin", OSD::Real(f64::from(self.twist_begin))),
|
||||
]),
|
||||
),
|
||||
(
|
||||
"profile",
|
||||
map_osd([
|
||||
("begin", OSD::Real(f64::from(self.profile_begin))),
|
||||
("curve", OSD::Integer(self.profile_curve)),
|
||||
("end", OSD::Real(f64::from(self.profile_end))),
|
||||
("hollow", OSD::Real(f64::from(self.profile_hollow))),
|
||||
]),
|
||||
),
|
||||
(
|
||||
"sculpt",
|
||||
map_osd([
|
||||
("id", OSD::UUID(self.sculpt_id)),
|
||||
("type", OSD::Integer(self.sculpt_type as i32)),
|
||||
]),
|
||||
),
|
||||
]);
|
||||
finish_map([
|
||||
("group-id", OSD::UUID(self.group_id)),
|
||||
("material", OSD::Integer(self.material as i32)),
|
||||
("name", OSD::String(self.name.clone())),
|
||||
("pos", OSD::from_vector3(self.position)?),
|
||||
("rotation", OSD::from_quaternion(self.rotation)?),
|
||||
("scale", OSD::from_vector3(self.scale)?),
|
||||
("extra_parameters", encode(&extras)?),
|
||||
("facelist", encode(&faces)?),
|
||||
("shape", shape),
|
||||
])
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn deserialize_generated(&mut self, map: &OSDMap) -> Result<(), Error> {
|
||||
self.group_id = required(map, "group-id")?.as_uuid()?;
|
||||
self.material = material_from_i32(required(map, "material")?.as_integer()?)?;
|
||||
self.name = required(map, "name")?.as_string()?;
|
||||
self.position = required(map, "pos")?.as_vector3()?;
|
||||
self.rotation = required(map, "rotation")?.as_quaternion()?;
|
||||
self.scale = required(map, "scale")?.as_vector3()?;
|
||||
self.extra_params = decode_array(&required(map, "extra_parameters")?)?;
|
||||
self.faces = decode_array(&required(map, "facelist")?)?;
|
||||
let shape_value = required(map, "shape")?;
|
||||
let shape = as_map(&shape_value)?;
|
||||
let path = as_map(required_from(shape, "path")?)?;
|
||||
macro_rules! real {
|
||||
($field:ident, $key:literal) => {
|
||||
self.$field = required_from(path, $key)?.as_real()? as f32;
|
||||
};
|
||||
}
|
||||
real!(path_begin, "begin");
|
||||
self.path_curve = required_from(path, "curve")?.as_integer()?;
|
||||
real!(path_end, "end");
|
||||
real!(radius_offset, "radius_offset");
|
||||
real!(revolutions, "revolutions");
|
||||
real!(scale_x, "scale_x");
|
||||
real!(scale_y, "scale_y");
|
||||
real!(shear_x, "shear_x");
|
||||
real!(shear_y, "shear_y");
|
||||
real!(skew, "skew");
|
||||
real!(taper_x, "taper_x");
|
||||
real!(taper_y, "taper_y");
|
||||
real!(twist, "twist");
|
||||
real!(twist_begin, "twist_begin");
|
||||
let profile = as_map(required_from(shape, "profile")?)?;
|
||||
self.profile_begin = required_from(profile, "begin")?.as_real()? as f32;
|
||||
self.profile_curve = required_from(profile, "curve")?.as_integer()?;
|
||||
self.profile_end = required_from(profile, "end")?.as_real()? as f32;
|
||||
self.profile_hollow = required_from(profile, "hollow")?.as_real()? as f32;
|
||||
let sculpt = as_map(required_from(shape, "sculpt")?)?;
|
||||
self.sculpt_id = required_from(sculpt, "id")?.as_uuid()?;
|
||||
self.sculpt_type = sculpt_type_from_i32(required_from(sculpt, "type")?.as_integer()?)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
trait GeneratedMessageObject {
|
||||
fn encode(&self) -> Result<OSD, Error>;
|
||||
}
|
||||
impl GeneratedMessageObject for UploadObjectAssetMessageObjectFace {
|
||||
fn encode(&self) -> Result<OSD, Error> {
|
||||
self.serialize_generated()?.copy()
|
||||
}
|
||||
}
|
||||
impl GeneratedMessageObject for UploadObjectAssetMessageObjectExtraParam {
|
||||
fn encode(&self) -> Result<OSD, Error> {
|
||||
self.serialize_generated()?.copy()
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneratedMessage for UploadObjectAssetMessage {
|
||||
fn new_generated() -> Self {
|
||||
Self {
|
||||
objects: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn serialize_generated(&self) -> Result<OSDMap, Error> {
|
||||
finish_map([("objects", encode_struct_array(&self.objects)?)])
|
||||
}
|
||||
fn deserialize_generated(&mut self, map: &OSDMap) -> Result<(), Error> {
|
||||
self.objects = decode_array(&required(map, "objects")?)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! upload_message_value {
|
||||
($($type:ty),+ $(,)?) => {
|
||||
$(impl MessageValue for $type {
|
||||
fn message_default() -> Self { <Self as GeneratedMessage>::new_generated() }
|
||||
fn to_message_osd(&self) -> Result<OSD, Error> { self.serialize_generated()?.copy() }
|
||||
fn from_message_osd(value: &OSD) -> Result<Self, Error> {
|
||||
let OSD::Map(values) = value else { return Err(Error::Argument); };
|
||||
let map = OSDMap::new_with_dictionary(values.clone())?;
|
||||
let mut output = <Self as GeneratedMessage>::new_generated();
|
||||
output.deserialize_generated(&map)?;
|
||||
Ok(output)
|
||||
}
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
upload_message_value!(
|
||||
UploadObjectAssetMessage,
|
||||
UploadObjectAssetMessageObject,
|
||||
UploadObjectAssetMessageObjectExtraParam,
|
||||
UploadObjectAssetMessageObjectFace,
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user