Implement native agent movement and teleportation (#60)
This commit is contained in:
@@ -25,19 +25,18 @@ use crate::{
|
||||
ViewerBenefitsEventArgs,
|
||||
};
|
||||
use crate::{
|
||||
AgentFlags, AgentManagerAgentMovement, AgentManagerAgentMovementAgentCamera, AgentState,
|
||||
ChatSessionMember, ChatType, EffectType, Error, GridClient, InstantMessageDialog,
|
||||
InstantMessageOnline, LookAtType, MoneyTransactionType, MuteEntry, PointAtType, Simulator,
|
||||
TransactionFlags, network_manager::CapsEventQueueCallback,
|
||||
AgentManagerAgentMovement, ChatSessionMember, ChatType, EffectType, Error, GridClient,
|
||||
InstantMessageDialog, InstantMessageOnline, LookAtType, MoneyTransactionType, MuteEntry,
|
||||
PointAtType, Simulator, TransactionFlags, network_manager::CapsEventQueueCallback,
|
||||
};
|
||||
use libremetaverse_structured_data::{OSD, OSDMap, OSDParser};
|
||||
use libremetaverse_types::compat::{EventHandler, Subscription, Uri};
|
||||
use libremetaverse_types::{Color4, Quaternion, UUID, Vector3, Vector3d};
|
||||
use libremetaverse_types::{Color4, UUID, Vector3, Vector3d};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt;
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::{Arc, Mutex, OnceLock, RwLock};
|
||||
use std::time::{Duration, Instant, UNIX_EPOCH};
|
||||
|
||||
const MAX_CHAT_BYTES: usize = 1023;
|
||||
@@ -127,12 +126,12 @@ fn parse_mute_list(text: &str) -> HashMap<String, MuteEntry> {
|
||||
result
|
||||
}
|
||||
|
||||
struct EventRegistryState<T> {
|
||||
pub(crate) struct EventRegistryState<T> {
|
||||
next_id: AtomicU64,
|
||||
handlers: Mutex<Vec<(u64, EventHandler<T>)>>,
|
||||
}
|
||||
|
||||
struct EventRegistry<T> {
|
||||
pub(crate) struct EventRegistry<T> {
|
||||
state: Arc<EventRegistryState<T>>,
|
||||
}
|
||||
|
||||
@@ -148,7 +147,7 @@ impl<T> Default for EventRegistry<T> {
|
||||
}
|
||||
|
||||
impl<T: Clone + 'static> EventRegistry<T> {
|
||||
fn subscribe(&self, handler: EventHandler<T>) -> Subscription {
|
||||
pub(crate) fn subscribe(&self, handler: EventHandler<T>) -> Subscription {
|
||||
let id = self.state.next_id.fetch_add(1, Ordering::Relaxed);
|
||||
mutex(&self.state.handlers).push((id, handler));
|
||||
let state = Arc::downgrade(&self.state);
|
||||
@@ -159,7 +158,7 @@ impl<T: Clone + 'static> EventRegistry<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn emit(&self, value: T) {
|
||||
pub(crate) fn emit(&self, value: T) {
|
||||
let handlers: Vec<_> = mutex(&self.state.handlers)
|
||||
.iter()
|
||||
.map(|(_, handler)| Arc::clone(handler))
|
||||
@@ -345,6 +344,7 @@ pub(crate) struct AgentManagerInner {
|
||||
network: Mutex<Option<crate::NetworkManager>>,
|
||||
raw_packet_subscription: Mutex<Option<Subscription>>,
|
||||
caps_subscriptions: Mutex<Vec<Subscription>>,
|
||||
movement: OnceLock<Arc<crate::agent_movement::AgentMovementRuntime>>,
|
||||
chat_from_simulator: EventRegistry<ChatEventArgs>,
|
||||
money_balance: EventRegistry<BalanceEventArgs>,
|
||||
money_balance_reply: EventRegistry<MoneyBalanceReplyEventArgs>,
|
||||
@@ -397,6 +397,7 @@ impl Default for AgentManagerInner {
|
||||
network: Mutex::new(None),
|
||||
raw_packet_subscription: Mutex::new(None),
|
||||
caps_subscriptions: Mutex::new(Vec::new()),
|
||||
movement: OnceLock::new(),
|
||||
chat_from_simulator: EventRegistry::default(),
|
||||
money_balance: EventRegistry::default(),
|
||||
money_balance_reply: EventRegistry::default(),
|
||||
@@ -420,6 +421,13 @@ impl Default for AgentManagerInner {
|
||||
|
||||
impl AgentManagerInner {
|
||||
fn handle_raw_packet(&self, event: crate::network_manager::RawPacketReceivedEventArgs) {
|
||||
if let Some(movement) = self.movement.get()
|
||||
&& movement
|
||||
.handle_raw_packet(event.packet_type, &event.data, event.simulator.clone())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
let result = match event.packet_type {
|
||||
crate::packets::PacketType::ChatFromSimulator => {
|
||||
self.handle_chat_packet(&event.data, event.simulator)
|
||||
@@ -716,6 +724,29 @@ impl AgentManagerInner {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn native_ids(&self, network: &crate::NetworkManager) -> (UUID, UUID) {
|
||||
let agent_id = *self
|
||||
.agent_id
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let session_id = *self
|
||||
.session_id
|
||||
.read()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
(
|
||||
if agent_id == UUID::zero() {
|
||||
network.native_agent_id()
|
||||
} else {
|
||||
agent_id
|
||||
},
|
||||
if session_id == UUID::zero() {
|
||||
network.native_session_id()
|
||||
} else {
|
||||
session_id
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn handle_caps_event(
|
||||
self: &Arc<Self>,
|
||||
client: Arc<GridClient>,
|
||||
@@ -723,6 +754,13 @@ impl AgentManagerInner {
|
||||
message: &dyn crate::interfaces::IMessage,
|
||||
simulator: Simulator,
|
||||
) {
|
||||
if let Some(movement) = self.movement.get()
|
||||
&& movement
|
||||
.handle_caps_event(name, message, simulator.clone())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
let result = match name {
|
||||
"ChatterBoxInvitation" => self.handle_chat_invitation(client, message, simulator),
|
||||
"ChatterBoxSessionEventReply" => self.handle_chat_session_event_reply(client, message),
|
||||
@@ -926,7 +964,7 @@ pub struct AgentManager {
|
||||
pub movement: AgentManagerAgentMovement,
|
||||
pub mute_list: Arc<RwLock<HashMap<String, MuteEntry>>>,
|
||||
pub signaled_animations: Arc<RwLock<HashMap<UUID, i32>>>,
|
||||
client: Arc<GridClient>,
|
||||
pub(crate) client: Arc<GridClient>,
|
||||
inner: Arc<AgentManagerInner>,
|
||||
}
|
||||
|
||||
@@ -980,6 +1018,9 @@ impl AgentManager {
|
||||
"ChatterBoxSessionAgentListUpdates",
|
||||
"SetDisplayNameReply",
|
||||
"NavMeshStatusUpdate",
|
||||
"TeleportFinish",
|
||||
"TeleportFailed",
|
||||
"CrossedRegion",
|
||||
] {
|
||||
let weak_inner = Arc::downgrade(&inner);
|
||||
let weak_client = Arc::downgrade(&client);
|
||||
@@ -996,16 +1037,17 @@ impl AgentManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
let movement_runtime = Arc::clone(inner.movement.get_or_init(|| {
|
||||
crate::agent_movement::AgentMovementRuntime::new(
|
||||
Arc::clone(&client),
|
||||
network.clone(),
|
||||
Arc::downgrade(&inner),
|
||||
)
|
||||
}));
|
||||
Ok(Self {
|
||||
agent_state_status: None,
|
||||
group_chat_sessions: Arc::clone(&inner.group_chat_sessions),
|
||||
movement: AgentManagerAgentMovement {
|
||||
body_rotation: Quaternion::identity(),
|
||||
camera: AgentManagerAgentMovementAgentCamera { far: 128.0 },
|
||||
flags: AgentFlags::NONE,
|
||||
head_rotation: Quaternion::identity(),
|
||||
state: AgentState::NONE,
|
||||
},
|
||||
movement: AgentManagerAgentMovement::from_runtime(movement_runtime),
|
||||
mute_list: Arc::clone(&inner.mute_list),
|
||||
signaled_animations: Arc::clone(&inner.signaled_animations),
|
||||
client,
|
||||
@@ -1040,6 +1082,9 @@ impl AgentManager {
|
||||
}
|
||||
mutex(&self.inner.raw_packet_subscription).take();
|
||||
mutex(&self.inner.caps_subscriptions).clear();
|
||||
if let Some(movement) = self.inner.movement.get() {
|
||||
movement.stop();
|
||||
}
|
||||
mutex(&self.inner.network).take();
|
||||
mutex(&self.inner.mute_xfers).clear();
|
||||
self.group_chat_sessions
|
||||
|
||||
3479
crates/libremetaverse/src/agent_movement.rs
Normal file
3479
crates/libremetaverse/src/agent_movement.rs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ extern crate self as libremetaverse;
|
||||
mod attention_catalog;
|
||||
mod agent_manager;
|
||||
mod agent_messages;
|
||||
mod agent_movement;
|
||||
mod bit_pack;
|
||||
mod caps;
|
||||
mod caps_http;
|
||||
|
||||
@@ -1011,6 +1011,7 @@ pub struct SimulatorData {
|
||||
pub wind_speeds: Option<Vec<Vector2>>,
|
||||
endpoint: std::net::SocketAddr,
|
||||
connected: AtomicBool,
|
||||
movement_complete: AtomicBool,
|
||||
handshake_complete: AtomicBool,
|
||||
handshake_wait: Condvar,
|
||||
handshake_wait_lock: Mutex<()>,
|
||||
@@ -1173,6 +1174,7 @@ impl Simulator {
|
||||
wind_speeds: None,
|
||||
endpoint: address,
|
||||
connected: AtomicBool::new(false),
|
||||
movement_complete: AtomicBool::new(false),
|
||||
handshake_complete: AtomicBool::new(false),
|
||||
handshake_wait: Condvar::new(),
|
||||
handshake_wait_lock: Mutex::new(()),
|
||||
@@ -1483,6 +1485,10 @@ impl Simulator {
|
||||
Ok(self.caps_running() || self.current_sim_caps_running())
|
||||
}
|
||||
|
||||
pub(crate) fn native_start_event_queue(&self) {
|
||||
self.start_current_event_queue();
|
||||
}
|
||||
|
||||
fn caps_running(&self) -> bool {
|
||||
read(&self.caps_state).as_ref().is_some_and(|inner| {
|
||||
Caps::native_from_inner(Arc::clone(inner), self.native_clone_without_caps())
|
||||
@@ -1615,6 +1621,15 @@ impl Simulator {
|
||||
self.connected.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn native_agent_movement_complete(&self) -> bool {
|
||||
self.movement_complete.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
pub(crate) fn native_set_agent_movement_complete(&self, value: bool) {
|
||||
self.movement_complete.store(value, Ordering::Release);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn native_set_connected_for_tests(&self, connected: bool) {
|
||||
self.connected.store(connected, Ordering::Release);
|
||||
|
||||
Reference in New Issue
Block a user