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:
@@ -17,12 +17,13 @@ use crate::messages::linden::{
|
||||
};
|
||||
use crate::{
|
||||
AgentAccessEventArgs, AgentDataReplyEventArgs, AgentExperiencesEventArgs,
|
||||
AgentPreferencesEventArgs, AnimationsChangedEventArgs, AvatarRenderInfoEventArgs,
|
||||
BalanceEventArgs, ChatEventArgs, ChatSessionMemberAddedEventArgs,
|
||||
AgentPreferencesEventArgs, AlertMessageEventArgs, AnimationsChangedEventArgs,
|
||||
AvatarRenderInfoEventArgs, BalanceEventArgs, ChatEventArgs, ChatSessionMemberAddedEventArgs,
|
||||
ChatSessionMemberLeftEventArgs, ExperienceInfoEventArgs, ExperiencePreferencesEventArgs,
|
||||
GroupChatJoinedEventArgs, MoneyBalanceReplyEventArgs, NavMeshStatusUpdateEventArgs,
|
||||
ProductInfoEventArgs, RegionExperiencesEventArgs, SetDisplayNameReplyEventArgs,
|
||||
ViewerBenefitsEventArgs,
|
||||
GroupChatJoinedEventArgs, LoadUrlEventArgs, MeanCollisionEventArgs, MoneyBalanceReplyEventArgs,
|
||||
NavMeshStatusUpdateEventArgs, ProductInfoEventArgs, RegionExperiencesEventArgs,
|
||||
ScriptControlEventArgs, ScriptDialogEventArgs, ScriptQuestionEventArgs,
|
||||
ScriptSensorReplyEventArgs, SetDisplayNameReplyEventArgs, ViewerBenefitsEventArgs,
|
||||
};
|
||||
use crate::{
|
||||
AgentManagerAgentMovement, ChatSessionMember, ChatType, EffectType, Error, GridClient,
|
||||
@@ -31,11 +32,11 @@ use crate::{
|
||||
};
|
||||
use libremetaverse_structured_data::{OSD, OSDMap, OSDParser};
|
||||
use libremetaverse_types::compat::{EventHandler, Subscription, Uri};
|
||||
use libremetaverse_types::{Color4, UUID, Vector3, Vector3d};
|
||||
use libremetaverse_types::{Color4, UUID, Vector3, Vector3d, Vector4};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt;
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Mutex, OnceLock, RwLock};
|
||||
use std::time::{Duration, Instant, UNIX_EPOCH};
|
||||
|
||||
@@ -317,8 +318,17 @@ pub(crate) struct AgentManagerInner {
|
||||
disposed: AtomicBool,
|
||||
agent_id: RwLock<UUID>,
|
||||
session_id: RwLock<UUID>,
|
||||
secure_session_id: RwLock<UUID>,
|
||||
first_name: RwLock<String>,
|
||||
last_name: RwLock<String>,
|
||||
start_location: RwLock<String>,
|
||||
look_at: RwLock<Vector3>,
|
||||
home_region_handle: RwLock<u64>,
|
||||
home_look_at: RwLock<Vector3>,
|
||||
local_id: RwLock<u32>,
|
||||
collision_plane: RwLock<Vector4>,
|
||||
health: RwLock<f32>,
|
||||
height_width_generation: AtomicU32,
|
||||
active_group: RwLock<UUID>,
|
||||
active_group_powers: RwLock<crate::GroupPowers>,
|
||||
agent_access: RwLock<String>,
|
||||
@@ -344,6 +354,7 @@ pub(crate) struct AgentManagerInner {
|
||||
network: Mutex<Option<crate::NetworkManager>>,
|
||||
raw_packet_subscription: Mutex<Option<Subscription>>,
|
||||
caps_subscriptions: Mutex<Vec<Subscription>>,
|
||||
login_callback: Mutex<Option<crate::NetworkManagerLoginResponseCallback>>,
|
||||
movement: OnceLock<Arc<crate::agent_movement::AgentMovementRuntime>>,
|
||||
chat_from_simulator: EventRegistry<ChatEventArgs>,
|
||||
money_balance: EventRegistry<BalanceEventArgs>,
|
||||
@@ -362,6 +373,13 @@ pub(crate) struct AgentManagerInner {
|
||||
set_display_name_reply: EventRegistry<SetDisplayNameReplyEventArgs>,
|
||||
nav_mesh_status_update: EventRegistry<NavMeshStatusUpdateEventArgs>,
|
||||
mute_list_updated: EventRegistry<()>,
|
||||
alert_message: EventRegistry<AlertMessageEventArgs>,
|
||||
load_url: EventRegistry<LoadUrlEventArgs>,
|
||||
mean_collision: EventRegistry<MeanCollisionEventArgs>,
|
||||
script_control_change: EventRegistry<ScriptControlEventArgs>,
|
||||
script_dialog: EventRegistry<ScriptDialogEventArgs>,
|
||||
script_question: EventRegistry<ScriptQuestionEventArgs>,
|
||||
script_sensor_reply: EventRegistry<ScriptSensorReplyEventArgs>,
|
||||
}
|
||||
|
||||
impl Default for AgentManagerInner {
|
||||
@@ -370,8 +388,17 @@ impl Default for AgentManagerInner {
|
||||
disposed: AtomicBool::new(false),
|
||||
agent_id: RwLock::new(UUID::zero()),
|
||||
session_id: RwLock::new(UUID::zero()),
|
||||
secure_session_id: RwLock::new(UUID::zero()),
|
||||
first_name: RwLock::new(String::new()),
|
||||
last_name: RwLock::new(String::new()),
|
||||
start_location: RwLock::new(String::new()),
|
||||
look_at: RwLock::new(Vector3::zero()),
|
||||
home_region_handle: RwLock::new(0),
|
||||
home_look_at: RwLock::new(Vector3::zero()),
|
||||
local_id: RwLock::new(0),
|
||||
collision_plane: RwLock::new(Vector4::zero()),
|
||||
health: RwLock::new(0.0),
|
||||
height_width_generation: AtomicU32::new(0),
|
||||
active_group: RwLock::new(UUID::zero()),
|
||||
active_group_powers: RwLock::new(crate::GroupPowers(0)),
|
||||
agent_access: RwLock::new(String::new()),
|
||||
@@ -397,6 +424,7 @@ impl Default for AgentManagerInner {
|
||||
network: Mutex::new(None),
|
||||
raw_packet_subscription: Mutex::new(None),
|
||||
caps_subscriptions: Mutex::new(Vec::new()),
|
||||
login_callback: Mutex::new(None),
|
||||
movement: OnceLock::new(),
|
||||
chat_from_simulator: EventRegistry::default(),
|
||||
money_balance: EventRegistry::default(),
|
||||
@@ -415,6 +443,13 @@ impl Default for AgentManagerInner {
|
||||
set_display_name_reply: EventRegistry::default(),
|
||||
nav_mesh_status_update: EventRegistry::default(),
|
||||
mute_list_updated: EventRegistry::default(),
|
||||
alert_message: EventRegistry::default(),
|
||||
load_url: EventRegistry::default(),
|
||||
mean_collision: EventRegistry::default(),
|
||||
script_control_change: EventRegistry::default(),
|
||||
script_dialog: EventRegistry::default(),
|
||||
script_question: EventRegistry::default(),
|
||||
script_sensor_reply: EventRegistry::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,6 +479,31 @@ impl AgentManagerInner {
|
||||
crate::packets::PacketType::AvatarAnimation => {
|
||||
self.handle_avatar_animation_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::AlertMessage => {
|
||||
self.handle_alert_message_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::AgentAlertMessage => {
|
||||
self.handle_agent_alert_message_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::HealthMessage => {
|
||||
self.handle_health_message_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::LoadURL => self.handle_load_url_packet(&event.data),
|
||||
crate::packets::PacketType::MeanCollisionAlert => {
|
||||
self.handle_mean_collision_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::ScriptControlChange => {
|
||||
self.handle_script_control_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::ScriptDialog => {
|
||||
self.handle_script_dialog_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::ScriptQuestion => {
|
||||
self.handle_script_question_packet(&event.data, event.simulator)
|
||||
}
|
||||
crate::packets::PacketType::ScriptSensorReply => {
|
||||
self.handle_script_sensor_reply_packet(&event.data)
|
||||
}
|
||||
crate::packets::PacketType::MuteListUpdate => {
|
||||
self.handle_mute_list_update_packet(&event.data, event.simulator)
|
||||
}
|
||||
@@ -458,6 +518,164 @@ impl AgentManagerInner {
|
||||
let _ = result;
|
||||
}
|
||||
|
||||
fn handle_alert_message_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::AlertMessagePacket>(data)?;
|
||||
let (notification_id, extra_params) =
|
||||
packet
|
||||
.alert_info
|
||||
.first()
|
||||
.map_or(Ok::<_, Error>((None, None)), |info| {
|
||||
let extra_params = if info.extra_params.is_empty() {
|
||||
None
|
||||
} else {
|
||||
match OSDParser::deserialize_with_bytes(info.extra_params.clone())? {
|
||||
OSD::Map(map) => Some(OSDMap::new_with_dictionary(map)?),
|
||||
_ => return Err(Error::InvalidOperation),
|
||||
}
|
||||
};
|
||||
Ok((Some(wire_string(info.message.clone())), extra_params))
|
||||
})?;
|
||||
self.alert_message.emit(AlertMessageEventArgs::new(
|
||||
wire_string(packet.alert_data.message),
|
||||
notification_id,
|
||||
extra_params,
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_agent_alert_message_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::AgentAlertMessagePacket>(data)?;
|
||||
self.alert_message.emit(AlertMessageEventArgs::new(
|
||||
wire_string(packet.alert_data.message),
|
||||
None,
|
||||
None,
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_health_message_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::HealthMessagePacket>(data)?;
|
||||
*self
|
||||
.health
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = packet.health_data.health;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_load_url_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::LoadURLPacket>(data)?;
|
||||
let data = packet.data;
|
||||
self.load_url.emit(LoadUrlEventArgs::new(
|
||||
wire_string(data.object_name),
|
||||
data.object_id,
|
||||
data.owner_id,
|
||||
data.owner_is_group,
|
||||
wire_string(data.message),
|
||||
wire_string(data.url),
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_mean_collision_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::MeanCollisionAlertPacket>(data)?;
|
||||
for collision in packet.mean_collision {
|
||||
let type_ = match collision.type_ {
|
||||
0 => crate::MeanCollisionType::None,
|
||||
1 => crate::MeanCollisionType::Bump,
|
||||
2 => crate::MeanCollisionType::LLPushObject,
|
||||
3 => crate::MeanCollisionType::SelectedObjectCollide,
|
||||
4 => crate::MeanCollisionType::ScriptedObjectCollide,
|
||||
5 => crate::MeanCollisionType::PhysicalObjectCollide,
|
||||
_ => return Err(Error::Argument),
|
||||
};
|
||||
self.mean_collision.emit(MeanCollisionEventArgs::new(
|
||||
type_,
|
||||
collision.perp,
|
||||
collision.victim,
|
||||
collision.mag,
|
||||
UNIX_EPOCH + Duration::from_secs(u64::from(collision.time)),
|
||||
)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_script_control_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::ScriptControlChangePacket>(data)?;
|
||||
for change in packet.data {
|
||||
self.script_control_change.emit(ScriptControlEventArgs::new(
|
||||
crate::ScriptControlChange(change.controls),
|
||||
change.pass_to_agent,
|
||||
change.take_controls,
|
||||
)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_script_dialog_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::ScriptDialogPacket>(data)?;
|
||||
let owner_id = packet
|
||||
.owner_data
|
||||
.first()
|
||||
.map_or(UUID::zero(), |owner| owner.owner_id);
|
||||
let buttons = packet
|
||||
.buttons
|
||||
.into_iter()
|
||||
.map(|button| wire_string(button.button_label))
|
||||
.collect();
|
||||
let dialog = packet.data;
|
||||
self.script_dialog.emit(ScriptDialogEventArgs::new(
|
||||
wire_string(dialog.message),
|
||||
wire_string(dialog.object_name),
|
||||
dialog.image_id,
|
||||
dialog.object_id,
|
||||
wire_string(dialog.first_name),
|
||||
wire_string(dialog.last_name),
|
||||
dialog.chat_channel,
|
||||
buttons,
|
||||
owner_id,
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_script_question_packet(
|
||||
&self,
|
||||
data: &[u8],
|
||||
simulator: Simulator,
|
||||
) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::ScriptQuestionPacket>(data)?;
|
||||
let question = packet.data;
|
||||
self.script_question.emit(ScriptQuestionEventArgs::new(
|
||||
simulator,
|
||||
question.task_id,
|
||||
question.item_id,
|
||||
wire_string(question.object_name),
|
||||
wire_string(question.object_owner),
|
||||
crate::ScriptPermission(question.questions),
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_script_sensor_reply_packet(&self, data: &[u8]) -> Result<(), Error> {
|
||||
let packet = decode_raw_packet::<crate::packets::ScriptSensorReplyPacket>(data)?;
|
||||
let requester_id = packet.requester.source_id;
|
||||
for sensed in packet.sensed_data {
|
||||
self.script_sensor_reply
|
||||
.emit(ScriptSensorReplyEventArgs::new(
|
||||
requester_id,
|
||||
sensed.group_id,
|
||||
wire_string(sensed.name),
|
||||
sensed.object_id,
|
||||
sensed.owner_id,
|
||||
sensed.position,
|
||||
sensed.range,
|
||||
sensed.rotation,
|
||||
crate::ScriptSensorTypeFlags(sensed.type_),
|
||||
sensed.velocity,
|
||||
)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_mute_list_update_packet(
|
||||
&self,
|
||||
data: &[u8],
|
||||
@@ -747,6 +965,81 @@ impl AgentManagerInner {
|
||||
)
|
||||
}
|
||||
|
||||
fn apply_login_response(&self, response: &crate::LoginResponseData) {
|
||||
*self
|
||||
.agent_id
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.agent_id();
|
||||
*self
|
||||
.session_id
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.session_id();
|
||||
*self
|
||||
.secure_session_id
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.secure_session_id();
|
||||
*self
|
||||
.first_name
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.first_name();
|
||||
*self
|
||||
.last_name
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.last_name();
|
||||
*self
|
||||
.start_location
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.start_location();
|
||||
*self
|
||||
.agent_access
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.agent_access();
|
||||
let look_at = response.look_at();
|
||||
*self
|
||||
.look_at
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = look_at;
|
||||
let home = response.home();
|
||||
*self
|
||||
.home_region_handle
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = home.region_handle;
|
||||
*self
|
||||
.home_look_at
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = home.look_at;
|
||||
*self
|
||||
.benefits
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.account_level_benefits();
|
||||
*self
|
||||
.active_gestures
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = response.gestures();
|
||||
if let Some(movement) = self.movement.get() {
|
||||
movement.set_home_position(home.position);
|
||||
let _ = movement.set_login_look_at(look_at);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_avatar_object_state(&self, local_id: u32, collision_plane: Vector4) {
|
||||
*self
|
||||
.local_id
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = local_id;
|
||||
*self
|
||||
.collision_plane
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = collision_plane;
|
||||
}
|
||||
|
||||
pub(crate) fn avatar_local_id(&self) -> u32 {
|
||||
*self
|
||||
.local_id
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
fn handle_caps_event(
|
||||
self: &Arc<Self>,
|
||||
client: Arc<GridClient>,
|
||||
@@ -1044,6 +1337,39 @@ impl AgentManager {
|
||||
Arc::downgrade(&inner),
|
||||
)
|
||||
}));
|
||||
{
|
||||
let mut callback = mutex(&inner.login_callback);
|
||||
if callback.is_none() {
|
||||
let weak = Arc::downgrade(&inner);
|
||||
let registered = crate::NetworkManagerLoginResponseCallback::from_handler(
|
||||
move |success, redirect, _message, _reason, response| {
|
||||
if success
|
||||
&& !redirect
|
||||
&& let (Some(inner), Some(response)) = (weak.upgrade(), response)
|
||||
{
|
||||
inner.apply_login_response(&response);
|
||||
}
|
||||
},
|
||||
);
|
||||
network.native_register_login_response_callback(
|
||||
registered.clone(),
|
||||
Some(vec![
|
||||
"agent_id".into(),
|
||||
"session_id".into(),
|
||||
"secure_session_id".into(),
|
||||
"first_name".into(),
|
||||
"last_name".into(),
|
||||
"start_location".into(),
|
||||
"agent_access".into(),
|
||||
"look_at".into(),
|
||||
"home".into(),
|
||||
"gestures".into(),
|
||||
"account_level_benefits".into(),
|
||||
]),
|
||||
)?;
|
||||
*callback = Some(registered);
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
agent_state_status: None,
|
||||
group_chat_sessions: Arc::clone(&inner.group_chat_sessions),
|
||||
@@ -1076,12 +1402,66 @@ impl AgentManager {
|
||||
self.inner.animations_changed.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_alert_message(
|
||||
&self,
|
||||
handler: EventHandler<AlertMessageEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.alert_message.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_load_url(
|
||||
&self,
|
||||
handler: EventHandler<LoadUrlEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.load_url.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_mean_collision(
|
||||
&self,
|
||||
handler: EventHandler<MeanCollisionEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.mean_collision.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_script_control_change(
|
||||
&self,
|
||||
handler: EventHandler<ScriptControlEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.script_control_change.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_script_dialog(
|
||||
&self,
|
||||
handler: EventHandler<ScriptDialogEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.script_dialog.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_script_question(
|
||||
&self,
|
||||
handler: EventHandler<ScriptQuestionEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.script_question.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_subscribe_script_sensor_reply(
|
||||
&self,
|
||||
handler: EventHandler<ScriptSensorReplyEventArgs>,
|
||||
) -> Subscription {
|
||||
self.inner.script_sensor_reply.subscribe(handler)
|
||||
}
|
||||
|
||||
pub(crate) fn native_dispose(&self) -> Result<(), Error> {
|
||||
if self.inner.disposed.swap(true, Ordering::AcqRel) {
|
||||
return Ok(());
|
||||
}
|
||||
mutex(&self.inner.raw_packet_subscription).take();
|
||||
mutex(&self.inner.caps_subscriptions).clear();
|
||||
if let Some(callback) = mutex(&self.inner.login_callback).take()
|
||||
&& let Some(network) = mutex(&self.inner.network).as_ref()
|
||||
{
|
||||
network.native_unregister_login_response_callback(&callback)?;
|
||||
}
|
||||
if let Some(movement) = self.inner.movement.get() {
|
||||
movement.stop();
|
||||
}
|
||||
@@ -1388,6 +1768,297 @@ impl AgentManager {
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
|
||||
}
|
||||
|
||||
pub(crate) fn native_secure_session_id(&self) -> UUID {
|
||||
*self
|
||||
.inner
|
||||
.secure_session_id
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_secure_session_id(&self, value: UUID) {
|
||||
*self
|
||||
.inner
|
||||
.secure_session_id
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
|
||||
}
|
||||
|
||||
pub(crate) fn native_start_location(&self) -> String {
|
||||
self.inner
|
||||
.start_location
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_start_location(&self, value: String) {
|
||||
*self
|
||||
.inner
|
||||
.start_location
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
|
||||
}
|
||||
|
||||
pub(crate) fn native_look_at(&self) -> Vector3 {
|
||||
*self
|
||||
.inner
|
||||
.look_at
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_look_at(&self, value: Vector3) {
|
||||
*self
|
||||
.inner
|
||||
.look_at
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
|
||||
let _ = self
|
||||
.inner
|
||||
.movement
|
||||
.get()
|
||||
.map(|movement| movement.set_login_look_at(value));
|
||||
}
|
||||
|
||||
pub(crate) fn native_home_region_handle(&self) -> u64 {
|
||||
*self
|
||||
.inner
|
||||
.home_region_handle
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_home_look_at(&self) -> Vector3 {
|
||||
*self
|
||||
.inner
|
||||
.home_look_at
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_local_id(&self) -> u32 {
|
||||
*self
|
||||
.inner
|
||||
.local_id
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_collision_plane(&self) -> Vector4 {
|
||||
*self
|
||||
.inner
|
||||
.collision_plane
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_health(&self) -> f32 {
|
||||
*self
|
||||
.inner
|
||||
.health
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_health(&self, value: f32) {
|
||||
*self
|
||||
.inner
|
||||
.health
|
||||
.write()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn native_grab(
|
||||
&self,
|
||||
object_local_id: u32,
|
||||
grab_offset: Vector3,
|
||||
uv_coord: Vector3,
|
||||
st_coord: Vector3,
|
||||
face_index: i32,
|
||||
position: Vector3,
|
||||
normal: Vector3,
|
||||
binormal: Vector3,
|
||||
) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::ObjectGrabPacket::new_with_constructor()?;
|
||||
packet.agent_data.agent_id = self.native_agent_id();
|
||||
packet.agent_data.session_id = self.native_session_id();
|
||||
packet.object_data.local_id = object_local_id;
|
||||
packet.object_data.grab_offset = grab_offset;
|
||||
let mut surface = crate::packets::ObjectGrabPacketSurfaceInfoBlock::new_with_constructor()?;
|
||||
surface.uv_coord = uv_coord;
|
||||
surface.st_coord = st_coord;
|
||||
surface.face_index = face_index;
|
||||
surface.position = position;
|
||||
surface.normal = normal;
|
||||
surface.binormal = binormal;
|
||||
packet.surface_info = vec![surface];
|
||||
self.send_current_packet(
|
||||
crate::packets::PacketType::ObjectGrab,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn native_grab_update(
|
||||
&self,
|
||||
object_id: UUID,
|
||||
grab_position: Vector3,
|
||||
grab_offset: Vector3,
|
||||
uv_coord: Vector3,
|
||||
st_coord: Vector3,
|
||||
face_index: i32,
|
||||
position: Vector3,
|
||||
normal: Vector3,
|
||||
binormal: Vector3,
|
||||
) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::ObjectGrabUpdatePacket::new_with_constructor()?;
|
||||
packet.agent_data.agent_id = self.native_agent_id();
|
||||
packet.agent_data.session_id = self.native_session_id();
|
||||
packet.object_data.object_id = object_id;
|
||||
packet.object_data.grab_offset_initial = grab_offset;
|
||||
packet.object_data.grab_position = grab_position;
|
||||
packet.object_data.time_since_last = 0;
|
||||
let mut surface =
|
||||
crate::packets::ObjectGrabUpdatePacketSurfaceInfoBlock::new_with_constructor()?;
|
||||
surface.uv_coord = uv_coord;
|
||||
surface.st_coord = st_coord;
|
||||
surface.face_index = face_index;
|
||||
surface.position = position;
|
||||
surface.normal = normal;
|
||||
surface.binormal = binormal;
|
||||
packet.surface_info = vec![surface];
|
||||
self.send_current_packet(
|
||||
crate::packets::PacketType::ObjectGrabUpdate,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn native_de_grab(
|
||||
&self,
|
||||
object_local_id: u32,
|
||||
uv_coord: Vector3,
|
||||
st_coord: Vector3,
|
||||
face_index: i32,
|
||||
position: Vector3,
|
||||
normal: Vector3,
|
||||
binormal: Vector3,
|
||||
) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::ObjectDeGrabPacket::new_with_constructor()?;
|
||||
packet.agent_data.agent_id = self.native_agent_id();
|
||||
packet.agent_data.session_id = self.native_session_id();
|
||||
packet.object_data.local_id = object_local_id;
|
||||
let mut surface =
|
||||
crate::packets::ObjectDeGrabPacketSurfaceInfoBlock::new_with_constructor()?;
|
||||
surface.uv_coord = uv_coord;
|
||||
surface.st_coord = st_coord;
|
||||
surface.face_index = face_index;
|
||||
surface.position = position;
|
||||
surface.normal = normal;
|
||||
surface.binormal = binormal;
|
||||
packet.surface_info = vec![surface];
|
||||
self.send_current_packet(
|
||||
crate::packets::PacketType::ObjectDeGrab,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
fn send_current_packet(
|
||||
&self,
|
||||
packet_type: crate::packets::PacketType,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
let simulator = self
|
||||
.client
|
||||
.network()
|
||||
.native_current_sim()
|
||||
.ok_or(Error::InvalidOperation)?;
|
||||
send_simulator_packet(&simulator, packet_type, data)
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_height_width(&self, height: u16, width: u16) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::AgentHeightWidthPacket::new_with_constructor()?;
|
||||
packet.agent_data.agent_id = self.native_agent_id();
|
||||
packet.agent_data.session_id = self.native_session_id();
|
||||
packet.agent_data.circuit_code = self.client.network().native_circuit_code();
|
||||
packet.height_width_block.height = height;
|
||||
packet.height_width_block.width = width;
|
||||
packet.height_width_block.gen_counter = self
|
||||
.inner
|
||||
.height_width_generation
|
||||
.fetch_add(1, Ordering::AcqRel);
|
||||
self.send_current_packet(
|
||||
crate::packets::PacketType::AgentHeightWidth,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_home(&self) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::SetStartLocationRequestPacket::new_with_constructor()?;
|
||||
packet.agent_data.agent_id = self.native_agent_id();
|
||||
packet.agent_data.session_id = self.native_session_id();
|
||||
packet.start_location_data.location_pos = self.native_movement_runtime().sim_position();
|
||||
packet.start_location_data.location_id = 1;
|
||||
packet.start_location_data.sim_name = Vec::new();
|
||||
packet.start_location_data.location_look_at =
|
||||
self.native_movement_runtime().camera_at_axis();
|
||||
self.send_current_packet(
|
||||
crate::packets::PacketType::SetStartLocationRequest,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn native_script_question_reply(
|
||||
&self,
|
||||
simulator: Simulator,
|
||||
item_id: UUID,
|
||||
task_id: UUID,
|
||||
permissions: crate::ScriptPermission,
|
||||
) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::ScriptAnswerYesPacket::new_with_constructor()?;
|
||||
packet.agent_data.agent_id = self.native_agent_id();
|
||||
packet.agent_data.session_id = self.native_session_id();
|
||||
packet.data.item_id = item_id;
|
||||
packet.data.task_id = task_id;
|
||||
packet.data.questions = permissions.0;
|
||||
send_simulator_packet(
|
||||
&simulator,
|
||||
crate::packets::PacketType::ScriptAnswerYes,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn native_request_script_sensor(
|
||||
&self,
|
||||
name: String,
|
||||
search_id: UUID,
|
||||
type_: crate::ScriptSensorTypeFlags,
|
||||
range: f32,
|
||||
arc: f32,
|
||||
request_id: UUID,
|
||||
simulator: Simulator,
|
||||
) -> Result<(), Error> {
|
||||
let mut packet = crate::packets::ScriptSensorRequestPacket::new_with_constructor()?;
|
||||
packet.requester.arc = arc;
|
||||
packet.requester.range = range;
|
||||
packet.requester.region_handle = simulator.handle;
|
||||
packet.requester.request_id = request_id;
|
||||
packet.requester.search_dir = libremetaverse_types::Quaternion::identity();
|
||||
packet.requester.search_id = search_id;
|
||||
packet.requester.search_name = name.into_bytes();
|
||||
packet.requester.search_pos = Vector3::zero();
|
||||
packet.requester.search_regions = 0;
|
||||
packet.requester.source_id = self.native_agent_id();
|
||||
packet.requester.type_ = type_.0;
|
||||
send_simulator_packet(
|
||||
&simulator,
|
||||
crate::packets::PacketType::ScriptSensorRequest,
|
||||
packet.to_bytes_with_method()?,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn native_last_name(&self) -> String {
|
||||
self.inner
|
||||
.last_name
|
||||
@@ -4064,6 +4735,7 @@ fn osd_uuid_array_contains(map: &OSDMap, key: &str, id: UUID) -> Result<bool, Er
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::too_many_lines)] // Protocol scenarios remain readable as contiguous exchanges.
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
|
||||
Reference in New Issue
Block a user