Complete networking integration gate (#58)
All checks were successful
Native code generation / deterministic (push) Successful in 12m1s
Imaging and meshing gate / native (push) Successful in 4m3s
Native Rust workspace compile / compile (push) Successful in 4m6s

This commit is contained in:
2026-08-09 19:45:06 +00:00
parent 1fd127bd8a
commit c8b2317e13
13 changed files with 978 additions and 397 deletions

View File

@@ -319,6 +319,24 @@ impl DownloadManager {
Ok(())
}
/// Number of URI-deduplicated downloads currently queued or executing.
#[must_use]
pub fn active_download_count(&self) -> usize {
mutex(&self.0.active).len()
}
/// Whether the dispatcher has completed its idempotent teardown.
#[must_use]
pub fn is_disposed(&self) -> bool {
self.0.disposed.load(Ordering::Acquire)
}
/// Whether a dispatcher thread is still owned by this manager.
#[must_use]
pub fn dispatcher_running(&self) -> bool {
mutex(&self.0.dispatcher).is_some()
}
#[must_use]
pub fn parallel_downloads(&self) -> i32 {
i32::try_from(self.0.parallel_downloads.load(Ordering::Acquire)).unwrap_or(i32::MAX)

View File

@@ -23945,393 +23945,62 @@ impl Simulator {
}
/// C# type: `T:LibreMetaverse.Simulator.SimStats`.
pub struct SimulatorSimStats;
impl SimulatorSimStats {
/// C# member: `M:LibreMetaverse.Simulator.SimStats.#ctor`.
pub fn new() -> Result<Self, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.#ctor")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.AddRecvBytes(System.Int64)`.
pub fn add_recv_bytes(&self, v: i64) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.AddRecvBytes(System.Int64)",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.AddSentBytes(System.Int64)`.
pub fn add_sent_bytes(&self, v: i64) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.AddSentBytes(System.Int64)",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetAndIncrementLastPingID`.
pub fn get_and_increment_last_ping_id(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.GetAndIncrementLastPingID",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetConnectTime`.
pub fn get_connect_time(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetConnectTime")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetDroppedPackets`.
pub fn get_dropped_packets(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.GetDroppedPackets",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetIncomingBPS`.
pub fn get_incoming_bps(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetIncomingBPS")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetLastPingSent`.
pub fn get_last_ping_sent(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetLastPingSent")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetOutgoingBPS`.
pub fn get_outgoing_bps(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetOutgoingBPS")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetReceivedPongs`.
pub fn get_received_pongs(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.GetReceivedPongs",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetReceivedResends`.
pub fn get_received_resends(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.GetReceivedResends",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetRecvBytes`.
pub fn get_recv_bytes(&self) -> Result<i64, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetRecvBytes")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetRecvPackets`.
pub fn get_recv_packets(&self) -> Result<i64, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetRecvPackets")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetResentPackets`.
pub fn get_resent_packets(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.GetResentPackets",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetSentBytes`.
pub fn get_sent_bytes(&self) -> Result<i64, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetSentBytes")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetSentPackets`.
pub fn get_sent_packets(&self) -> Result<i64, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetSentPackets")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetSentPings`.
pub fn get_sent_pings(&self) -> Result<i32, crate::Error> {
libremetaverse_types::not_implemented("M:LibreMetaverse.Simulator.SimStats.GetSentPings")
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementDroppedPackets`.
pub fn increment_dropped_packets(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementDroppedPackets",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementReceivedPongs`.
pub fn increment_received_pongs(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementReceivedPongs",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementReceivedResends`.
pub fn increment_received_resends(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementReceivedResends",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementRecvPackets`.
pub fn increment_recv_packets(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementRecvPackets",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementResentPackets`.
pub fn increment_resent_packets(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementResentPackets",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementSentPackets`.
pub fn increment_sent_packets(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementSentPackets",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementSentPings`.
pub fn increment_sent_pings(&self) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.IncrementSentPings",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetConnectTime(System.Int32)`.
pub fn set_connect_time(&self, v: i32) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.SetConnectTime(System.Int32)",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetIncomingBPS(System.Int32)`.
pub fn set_incoming_bps(&self, v: i32) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.SetIncomingBPS(System.Int32)",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetLastPingSent(System.Int32)`.
pub fn set_last_ping_sent(&self, v: i32) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.SetLastPingSent(System.Int32)",
)
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetOutgoingBPS(System.Int32)`.
pub fn set_outgoing_bps(&self, v: i32) -> Result<(), crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Simulator.SimStats.SetOutgoingBPS(System.Int32)",
)
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ActiveScripts`.
pub fn active_scripts(&self) -> i32 {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.ActiveScripts"
)
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.ActiveScripts`.
pub fn set_active_scripts(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.ActiveScripts"
)
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.AgentTime`.
pub fn agent_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.AgentTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.AgentTime`.
pub fn set_agent_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.AgentTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.AgentUpdates`.
pub fn agent_updates(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.AgentUpdates")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.AgentUpdates`.
pub fn set_agent_updates(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.AgentUpdates")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.Agents`.
pub fn agents(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.Agents")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.Agents`.
pub fn set_agents(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.Agents")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ChildAgents`.
pub fn child_agents(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ChildAgents")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.ChildAgents`.
pub fn set_child_agents(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ChildAgents")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.Dilation`.
pub fn dilation(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.Dilation")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.Dilation`.
pub fn set_dilation(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.Dilation")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.FPS`.
pub fn fps(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.FPS")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.FPS`.
pub fn set_fps(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.FPS")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.FrameTime`.
pub fn frame_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.FrameTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.FrameTime`.
pub fn set_frame_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.FrameTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.INPPS`.
pub fn inpps(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.INPPS")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.INPPS`.
pub fn set_inpps(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.INPPS")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ImageTime`.
pub fn image_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ImageTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.ImageTime`.
pub fn set_image_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ImageTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.LSLIPS`.
pub fn lslips(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.LSLIPS")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.LSLIPS`.
pub fn set_lslips(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.LSLIPS")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.LastLag`.
pub fn last_lag(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.LastLag")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.LastLag`.
pub fn set_last_lag(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.LastLag")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.MissedPings`.
pub fn missed_pings(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.MissedPings")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.MissedPings`.
pub fn set_missed_pings(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.MissedPings")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.NetTime`.
pub fn net_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.NetTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.NetTime`.
pub fn set_net_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.NetTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.OUTPPS`.
pub fn outpps(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.OUTPPS")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.OUTPPS`.
pub fn set_outpps(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.OUTPPS")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.Objects`.
pub fn objects(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.Objects")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.Objects`.
pub fn set_objects(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.Objects")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.OtherTime`.
pub fn other_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.OtherTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.OtherTime`.
pub fn set_other_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.OtherTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PendingDownloads`.
pub fn pending_downloads(&self) -> i32 {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.PendingDownloads"
)
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.PendingDownloads`.
pub fn set_pending_downloads(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.PendingDownloads"
)
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PendingLocalUploads`.
pub fn pending_local_uploads(&self) -> i32 {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.PendingLocalUploads"
)
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.PendingLocalUploads`.
pub fn set_pending_local_uploads(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.PendingLocalUploads"
)
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PendingUploads`.
pub fn pending_uploads(&self) -> i32 {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.PendingUploads"
)
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.PendingUploads`.
pub fn set_pending_uploads(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.PendingUploads"
)
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PhysicsFPS`.
pub fn physics_fps(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.PhysicsFPS")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.PhysicsFPS`.
pub fn set_physics_fps(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.PhysicsFPS")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PhysicsTime`.
pub fn physics_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.PhysicsTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.PhysicsTime`.
pub fn set_physics_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.PhysicsTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ResidentSize`.
pub fn resident_size(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ResidentSize")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.ResidentSize`.
pub fn set_resident_size(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ResidentSize")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ScriptTime`.
pub fn script_time(&self) -> f32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ScriptTime")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.ScriptTime`.
pub fn set_script_time(&mut self, value: f32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.ScriptTime")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ScriptedObjects`.
pub fn scripted_objects(&self) -> i32 {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.ScriptedObjects"
)
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.ScriptedObjects`.
pub fn set_scripted_objects(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!(
"P:LibreMetaverse.Simulator.SimStats.ScriptedObjects"
)
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.UnackedBytes`.
pub fn unacked_bytes(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.UnackedBytes")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.UnackedBytes`.
pub fn set_unacked_bytes(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.UnackedBytes")
}
/// C# member: `P:LibreMetaverse.Simulator.SimStats.VirtualSize`.
pub fn virtual_size(&self) -> i32 {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.VirtualSize")
}
/// Setter for C# member: `P:LibreMetaverse.Simulator.SimStats.VirtualSize`.
pub fn set_virtual_size(&mut self, value: i32) {
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Simulator.SimStats.VirtualSize")
}
}
/// C# member: `M:LibreMetaverse.Simulator.SimStats.#ctor`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.AddRecvBytes(System.Int64)`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.AddSentBytes(System.Int64)`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetAndIncrementLastPingID`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetConnectTime`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetDroppedPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetIncomingBPS`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetLastPingSent`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetOutgoingBPS`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetReceivedPongs`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetReceivedResends`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetRecvBytes`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetRecvPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetResentPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetSentBytes`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetSentPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.GetSentPings`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementDroppedPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementReceivedPongs`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementReceivedResends`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementRecvPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementResentPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementSentPackets`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.IncrementSentPings`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetConnectTime(System.Int32)`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetIncomingBPS(System.Int32)`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetLastPingSent(System.Int32)`.
/// C# member: `M:LibreMetaverse.Simulator.SimStats.SetOutgoingBPS(System.Int32)`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ActiveScripts`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.AgentTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.AgentUpdates`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.Agents`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ChildAgents`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.Dilation`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.FPS`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.FrameTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.INPPS`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ImageTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.LSLIPS`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.LastLag`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.MissedPings`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.NetTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.OUTPPS`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.Objects`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.OtherTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PendingDownloads`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PendingLocalUploads`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PendingUploads`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PhysicsFPS`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.PhysicsTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ResidentSize`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ScriptTime`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.ScriptedObjects`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.UnackedBytes`.
/// C# member: `P:LibreMetaverse.Simulator.SimStats.VirtualSize`.
pub use crate::sim_stats::SimulatorSimStats;
/// C# type: `T:LibreMetaverse.SimulatorDataPool`.
pub struct SimulatorDataPool {

View File

@@ -23,6 +23,7 @@ mod network_manager;
#[rustfmt::skip]
pub mod packet_catalog;
mod packet_wire;
mod sim_stats;
mod skeleton;
#[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator.
mod skeleton_catalog;

View File

@@ -16,7 +16,7 @@ use crate::packets::{
AgentPausePacket, AgentResumePacket, CloseCircuitPacket, CompleteAgentMovementPacket,
CompletePingCheckPacket, GenericStreamingMessagePacket, KickUserPacket, LogoutReplyPacket,
LogoutRequestPacket, Packet, PacketType, RegionHandshakePacket, RegionHandshakeReplyPacket,
StartPingCheckPacket, UseCircuitCodePacket,
SimStatsPacket, StartPingCheckPacket, UseCircuitCodePacket,
};
use crate::udp_transport::{UDPBase, UDPPacketBuffer, UdpPacketHandler, UdpTransportConfig};
use crate::{
@@ -35,7 +35,7 @@ use std::fmt;
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU8, AtomicU32, AtomicU64, Ordering};
use std::sync::mpsc::{Receiver, RecvTimeoutError, SyncSender, sync_channel};
use std::sync::{Arc, Condvar, Mutex, RwLock, Weak};
use std::sync::{Arc, Condvar, Mutex, OnceLock, RwLock, Weak};
use std::thread::{self, JoinHandle};
use std::time::Duration;
@@ -96,6 +96,13 @@ fn positive_millisecond_duration(value: i32) -> Duration {
Duration::from_millis(u64::try_from(value.max(1)).unwrap_or(1))
}
fn environment_tick_count() -> i32 {
static START: OnceLock<std::time::Instant> = OnceLock::new();
let elapsed = START.get_or_init(std::time::Instant::now).elapsed();
let wrapped = u32::try_from(elapsed.as_millis() & u128::from(u32::MAX)).unwrap_or_default();
wrapped.cast_signed()
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum LogoutWaitOutcome {
Reply,
@@ -1011,7 +1018,6 @@ pub struct SimulatorData {
manager: Mutex<Weak<NetworkManagerInner>>,
transport: UDPBase,
transport_thread: Mutex<Option<TransportThread>>,
ping_id: AtomicU32,
pause_serial: AtomicU32,
}
@@ -1138,7 +1144,7 @@ impl Simulator {
sim_version: String::new(),
size_x: size_x.unwrap_or(Self::DEFAULT_REGION_SIZE_X),
size_y: size_y.unwrap_or(Self::DEFAULT_REGION_SIZE_Y),
stats: SimulatorSimStats,
stats: SimulatorSimStats::default(),
terrain: Vec::new(),
terrain_base0: UUID::zero(),
terrain_base1: UUID::zero(),
@@ -1174,7 +1180,6 @@ impl Simulator {
manager: Mutex::new(Weak::new()),
transport,
transport_thread: Mutex::new(None),
ping_id: AtomicU32::new(0),
pause_serial: AtomicU32::new(0),
});
*mutex(&simulator_reference) = Arc::downgrade(&data);
@@ -1265,6 +1270,7 @@ impl Simulator {
}
}
self.connected.store(true, Ordering::Release);
self.stats.set_connect_time(environment_tick_count())?;
self.handshake_complete.store(false, Ordering::Release);
drop(transport_thread);
self.native_use_circuit_code(true)?;
@@ -1401,8 +1407,9 @@ impl Simulator {
pub fn native_send_ping(&self) -> Result<(), Error> {
let mut ping = StartPingCheckPacket::new_with_constructor()?;
ping.ping_id.ping_id = self.ping_id.fetch_add(1, Ordering::Relaxed).to_le_bytes()[0];
ping.ping_id.ping_id = self.stats.get_and_increment_last_ping_id()?.to_le_bytes()[0];
ping.ping_id.oldest_unacked = 0;
self.stats.set_last_ping_sent(environment_tick_count())?;
let data = ping.to_bytes_with_method()?;
self.native_send_packet_data(
data.clone(),
@@ -1658,6 +1665,16 @@ impl UdpPacketHandler for SimulatorUdpHandler {
else {
return;
};
let _ = simulator
.stats
.add_recv_bytes(i64::from(buffer.data_length));
let _ = simulator.stats.increment_recv_packets();
if payload
.first()
.is_some_and(|flags| flags & Helpers::MSG_RESENT != 0)
{
let _ = simulator.stats.increment_received_resends();
}
simulator.note_packet_received(packet.type_);
let manager = mutex(&simulator.manager).upgrade();
if let Some(manager) = manager {
@@ -1674,11 +1691,29 @@ impl UdpPacketHandler for SimulatorUdpHandler {
return;
};
let simulator = Simulator { caps: None, data };
let _ = simulator
.stats
.add_sent_bytes(i64::try_from(bytes_sent).unwrap_or(i64::MAX));
let _ = simulator.stats.increment_sent_packets();
if buffer
.data
.first()
.is_some_and(|flags| flags & Helpers::MSG_RESENT != 0)
{
let _ = simulator.stats.increment_resent_packets();
}
let manager = mutex(&simulator.manager).upgrade();
if let Some(manager) = manager {
manager.raise_packet_sent(buffer.data, bytes_sent, simulator);
}
}
fn packet_dropped(&self) {
let Some(data) = mutex(&self.simulator).upgrade() else {
return;
};
let _ = data.stats.increment_dropped_packets();
}
}
#[derive(Clone)]
@@ -1929,6 +1964,9 @@ impl NetworkManagerInner {
simulator.handshake_complete.store(true, Ordering::Release);
simulator.handshake_wait.notify_all();
}
PacketType::CompletePingCheck => {
simulator.stats.record_pong(environment_tick_count());
}
PacketType::StartPingCheck => {
let Some(raw_data) = raw_data else {
return;
@@ -2022,6 +2060,40 @@ impl NetworkManagerInner {
"ClientInitiated".to_owned(),
);
}
PacketType::SimStats => {
if !self.client.settings_ref().packets.enable_sim_stats {
return;
}
let Some(raw_data) = raw_data else {
return;
};
let Ok(mut incoming) = SimStatsPacket::new_with_constructor() else {
return;
};
let Ok(mut packet_end) = i32::try_from(raw_data.len()) else {
return;
};
packet_end -= 1;
let mut position = 0;
let mut zero_buffer =
vec![0_u8; UdpTransportConfig::default().max_decoded_packet_size];
if incoming
.from_bytes_with_bytes_int32_int32_bytes(
raw_data.to_vec(),
&mut position,
&mut packet_end,
Some(&mut zero_buffer),
)
.is_err()
{
return;
}
for stat in incoming.stat {
simulator
.stats
.apply_server_stat(stat.stat_id, stat.stat_value);
}
}
PacketType::DisableSimulator => {
let _ = self.disconnect_simulator(simulator.clone(), false);
}
@@ -2196,8 +2268,8 @@ impl NetworkManagerInner {
crate::NetworkManagerDisconnectType::NetworkTimeout,
"NetworkTimeout".to_owned(),
);
} else {
let _ = current.native_send_ping();
} else if current.native_send_ping().is_ok() {
let _ = current.stats.increment_sent_pings();
}
}

View File

@@ -0,0 +1,347 @@
//! Thread-safe simulator statistics matching `Simulator.SimStats`.
#![allow(clippy::missing_errors_doc)] // Result shapes are fixed by the compatibility map.
use crate::Error;
use std::fmt;
use std::sync::atomic::{AtomicI32, AtomicI64, AtomicU32, Ordering};
fn csharp_convert_to_i32(value: f32) -> Option<i32> {
let rounded = value.round_ties_even();
if !rounded.is_finite() || !(-2_147_483_648.0..2_147_483_648.0).contains(&rounded) {
return None;
}
#[allow(clippy::cast_possible_truncation)]
Some(rounded as i32)
}
macro_rules! integer_property {
($get:ident, $set:ident, $field:ident) => {
#[must_use]
pub fn $get(&self) -> i32 {
self.$field.load(Ordering::Acquire)
}
pub fn $set(&mut self, value: i32) {
self.$field.store(value, Ordering::Release);
}
};
}
macro_rules! float_property {
($get:ident, $set:ident, $field:ident) => {
#[must_use]
pub fn $get(&self) -> f32 {
f32::from_bits(self.$field.load(Ordering::Acquire))
}
pub fn $set(&mut self, value: f32) {
self.$field.store(value.to_bits(), Ordering::Release);
}
};
}
#[derive(Default)]
pub struct SimulatorSimStats {
sent_packets: AtomicI64,
recv_packets: AtomicI64,
sent_bytes: AtomicI64,
recv_bytes: AtomicI64,
connect_time: AtomicI32,
resent_packets: AtomicI32,
received_resends: AtomicI32,
dropped_packets: AtomicI32,
sent_pings: AtomicI32,
received_pongs: AtomicI32,
incoming_bps: AtomicI32,
outgoing_bps: AtomicI32,
last_ping_sent: AtomicI32,
last_ping_id: AtomicI32,
last_lag: AtomicI32,
missed_pings: AtomicI32,
dilation: AtomicU32,
fps: AtomicI32,
physics_fps: AtomicU32,
agent_updates: AtomicU32,
frame_time: AtomicU32,
net_time: AtomicU32,
physics_time: AtomicU32,
image_time: AtomicU32,
script_time: AtomicU32,
agent_time: AtomicU32,
other_time: AtomicU32,
objects: AtomicI32,
scripted_objects: AtomicI32,
agents: AtomicI32,
child_agents: AtomicI32,
active_scripts: AtomicI32,
lslips: AtomicI32,
inpps: AtomicI32,
outpps: AtomicI32,
pending_downloads: AtomicI32,
pending_uploads: AtomicI32,
virtual_size: AtomicI32,
resident_size: AtomicI32,
pending_local_uploads: AtomicI32,
unacked_bytes: AtomicI32,
}
impl fmt::Debug for SimulatorSimStats {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("SimulatorSimStats")
.field("sent_packets", &self.sent_packets.load(Ordering::Relaxed))
.field("recv_packets", &self.recv_packets.load(Ordering::Relaxed))
.field("sent_bytes", &self.sent_bytes.load(Ordering::Relaxed))
.field("recv_bytes", &self.recv_bytes.load(Ordering::Relaxed))
.field(
"dropped_packets",
&self.dropped_packets.load(Ordering::Relaxed),
)
.finish_non_exhaustive()
}
}
impl SimulatorSimStats {
pub fn new() -> Result<Self, Error> {
Ok(Self::default())
}
pub fn add_recv_bytes(&self, value: i64) -> Result<(), Error> {
self.recv_bytes.fetch_add(value, Ordering::SeqCst);
Ok(())
}
pub fn add_sent_bytes(&self, value: i64) -> Result<(), Error> {
self.sent_bytes.fetch_add(value, Ordering::SeqCst);
Ok(())
}
pub fn get_and_increment_last_ping_id(&self) -> Result<i32, Error> {
Ok(self.last_ping_id.fetch_add(1, Ordering::SeqCst))
}
pub fn get_connect_time(&self) -> Result<i32, Error> {
Ok(self.connect_time.load(Ordering::SeqCst))
}
pub fn get_dropped_packets(&self) -> Result<i32, Error> {
Ok(self.dropped_packets.load(Ordering::SeqCst))
}
pub fn get_incoming_bps(&self) -> Result<i32, Error> {
Ok(self.incoming_bps.load(Ordering::SeqCst))
}
pub fn get_last_ping_sent(&self) -> Result<i32, Error> {
Ok(self.last_ping_sent.load(Ordering::SeqCst))
}
pub fn get_outgoing_bps(&self) -> Result<i32, Error> {
Ok(self.outgoing_bps.load(Ordering::SeqCst))
}
pub fn get_received_pongs(&self) -> Result<i32, Error> {
Ok(self.received_pongs.load(Ordering::SeqCst))
}
pub fn get_received_resends(&self) -> Result<i32, Error> {
Ok(self.received_resends.load(Ordering::SeqCst))
}
pub fn get_recv_bytes(&self) -> Result<i64, Error> {
Ok(self.recv_bytes.load(Ordering::SeqCst))
}
pub fn get_recv_packets(&self) -> Result<i64, Error> {
Ok(self.recv_packets.load(Ordering::SeqCst))
}
pub fn get_resent_packets(&self) -> Result<i32, Error> {
Ok(self.resent_packets.load(Ordering::SeqCst))
}
pub fn get_sent_bytes(&self) -> Result<i64, Error> {
Ok(self.sent_bytes.load(Ordering::SeqCst))
}
pub fn get_sent_packets(&self) -> Result<i64, Error> {
Ok(self.sent_packets.load(Ordering::SeqCst))
}
pub fn get_sent_pings(&self) -> Result<i32, Error> {
Ok(self.sent_pings.load(Ordering::SeqCst))
}
pub fn increment_dropped_packets(&self) -> Result<(), Error> {
self.dropped_packets.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn increment_received_pongs(&self) -> Result<(), Error> {
self.received_pongs.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn increment_received_resends(&self) -> Result<(), Error> {
self.received_resends.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn increment_recv_packets(&self) -> Result<(), Error> {
self.recv_packets.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn increment_resent_packets(&self) -> Result<(), Error> {
self.resent_packets.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn increment_sent_packets(&self) -> Result<(), Error> {
self.sent_packets.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn increment_sent_pings(&self) -> Result<(), Error> {
self.sent_pings.fetch_add(1, Ordering::SeqCst);
Ok(())
}
pub fn set_connect_time(&self, value: i32) -> Result<(), Error> {
self.connect_time.store(value, Ordering::SeqCst);
Ok(())
}
pub fn set_incoming_bps(&self, value: i32) -> Result<(), Error> {
self.incoming_bps.store(value, Ordering::SeqCst);
Ok(())
}
pub fn set_last_ping_sent(&self, value: i32) -> Result<(), Error> {
self.last_ping_sent.store(value, Ordering::SeqCst);
Ok(())
}
pub fn set_outgoing_bps(&self, value: i32) -> Result<(), Error> {
self.outgoing_bps.store(value, Ordering::SeqCst);
Ok(())
}
pub(crate) fn record_pong(&self, tick_count: i32) {
let sent = self.last_ping_sent.load(Ordering::Acquire);
self.last_lag
.store(tick_count.wrapping_sub(sent), Ordering::Release);
self.received_pongs.fetch_add(1, Ordering::SeqCst);
}
pub(crate) fn apply_server_stat(&self, id: u32, value: f32) {
let float = |field: &AtomicU32| field.store(value.to_bits(), Ordering::Release);
let integer = |field: &AtomicI32| {
if let Some(value) = csharp_convert_to_i32(value) {
field.store(value, Ordering::Release);
}
};
match id {
0 => float(&self.dilation),
1 => integer(&self.fps),
2 => float(&self.physics_fps),
3 => float(&self.agent_updates),
4 => float(&self.frame_time),
5 => float(&self.net_time),
6 => float(&self.other_time),
7 => float(&self.physics_time),
8 => float(&self.agent_time),
9 => float(&self.image_time),
10 => float(&self.script_time),
11 => integer(&self.objects),
12 => integer(&self.scripted_objects),
13 => integer(&self.agents),
14 => integer(&self.child_agents),
15 => integer(&self.active_scripts),
16 => integer(&self.lslips),
17 => integer(&self.inpps),
18 => integer(&self.outpps),
19 => integer(&self.pending_downloads),
20 => integer(&self.pending_uploads),
21 => integer(&self.virtual_size),
22 => integer(&self.resident_size),
23 => integer(&self.pending_local_uploads),
24 => integer(&self.unacked_bytes),
_ => {}
}
}
integer_property!(active_scripts, set_active_scripts, active_scripts);
float_property!(agent_time, set_agent_time, agent_time);
float_property!(agent_updates, set_agent_updates, agent_updates);
integer_property!(agents, set_agents, agents);
integer_property!(child_agents, set_child_agents, child_agents);
float_property!(dilation, set_dilation, dilation);
integer_property!(fps, set_fps, fps);
float_property!(frame_time, set_frame_time, frame_time);
integer_property!(inpps, set_inpps, inpps);
float_property!(image_time, set_image_time, image_time);
integer_property!(lslips, set_lslips, lslips);
integer_property!(last_lag, set_last_lag, last_lag);
integer_property!(missed_pings, set_missed_pings, missed_pings);
float_property!(net_time, set_net_time, net_time);
integer_property!(outpps, set_outpps, outpps);
integer_property!(objects, set_objects, objects);
float_property!(other_time, set_other_time, other_time);
integer_property!(pending_downloads, set_pending_downloads, pending_downloads);
integer_property!(
pending_local_uploads,
set_pending_local_uploads,
pending_local_uploads
);
integer_property!(pending_uploads, set_pending_uploads, pending_uploads);
float_property!(physics_fps, set_physics_fps, physics_fps);
float_property!(physics_time, set_physics_time, physics_time);
integer_property!(resident_size, set_resident_size, resident_size);
float_property!(script_time, set_script_time, script_time);
integer_property!(scripted_objects, set_scripted_objects, scripted_objects);
integer_property!(unacked_bytes, set_unacked_bytes, unacked_bytes);
integer_property!(virtual_size, set_virtual_size, virtual_size);
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use std::thread;
#[test]
fn counters_are_atomic_and_properties_preserve_float_bits() {
let stats = Arc::new(SimulatorSimStats::new().unwrap());
let workers: Vec<_> = (0..4)
.map(|_| {
let stats = Arc::clone(&stats);
thread::spawn(move || {
for _ in 0..1_000 {
stats.increment_recv_packets().unwrap();
stats.add_recv_bytes(7).unwrap();
}
})
})
.collect();
for worker in workers {
worker.join().unwrap();
}
assert_eq!(stats.get_recv_packets().unwrap(), 4_000);
assert_eq!(stats.get_recv_bytes().unwrap(), 28_000);
assert_eq!(stats.get_and_increment_last_ping_id().unwrap(), 0);
assert_eq!(stats.get_and_increment_last_ping_id().unwrap(), 1);
let mut stats = Arc::try_unwrap(stats).ok().unwrap();
stats.set_dilation(f32::from_bits(0x7fc0_1234));
assert_eq!(stats.dilation().to_bits(), 0x7fc0_1234);
stats.apply_server_stat(1, 44.5);
assert_eq!(stats.fps(), 44);
stats.apply_server_stat(1, 45.5);
assert_eq!(stats.fps(), 46);
stats.apply_server_stat(1, f32::NAN);
assert_eq!(stats.fps(), 46);
}
}