diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 65f839533a..f39eb0c662 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -825,6 +825,8 @@ namespace OpenSim.Framework /// event UpdateAgent OnAgentUpdate; + event UpdateAgent OnAgentCameraUpdate; + event AgentRequestSit OnAgentRequestSit; event AgentSit OnAgentSit; event AvatarPickerRequest OnAvatarPickerRequest; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 66a8ea7209..6c58aaca95 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; @@ -357,9 +358,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods /// cannot retain a reference to it outside of that method. /// - private AgentUpdateArgs m_lastAgentUpdateArgs = new AgentUpdateArgs(); - private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); + private float qdelta1; + private float qdelta2; + private float vdelta1; + private float vdelta2; + private float vdelta3; + private float vdelta4; protected Dictionary m_packetHandlers = new Dictionary(); protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers @@ -5571,57 +5576,75 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Scene/Avatar + private const float QDELTA = 0.01f; + private const float VDELTA = 0.01f; + /// /// This checks the update significance against the last update made. /// /// Can only be called by one thread at a time - /// /returns> + /// /// public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - // These should be ordered from most-likely to - // least likely to change. I've made an initial - // guess at that. + return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); + } + + /// + /// This checks the movement/state update significance against the last update made. + /// + /// Can only be called by one thread at a time + /// + /// + public bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + { + qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); + qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); if ( - /* These 4 are the worst offenders! We should consider ignoring most of them. + (qdelta1 > QDELTA) || + // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack + //(qdelta2 > QDELTA * 10) || + (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) || + (x.Far != m_thisAgentUpdateArgs.Far) || + (x.Flags != m_thisAgentUpdateArgs.Flags) || + (x.State != m_thisAgentUpdateArgs.State) + ) + { + //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", + // qdelta1, qdelta2); + //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3} (Thread {4})", + // x.ControlFlags, x.Flags, x.Far, x.State, Thread.CurrentThread.Name); + return true; + } + + return false; + } + + /// + /// This checks the camera update significance against the last update made. + /// + /// Can only be called by one thread at a time + /// + /// + public bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + { + vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); + vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); + vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); + vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); + if ( + /* These 4 are the worst offenders! * With Singularity, there is a bug where sometimes the spam on these doesn't stop */ - (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || - (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || - (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || - (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || - /* */ - (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || - (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || - (x.Far != m_lastAgentUpdateArgs.Far) || - (x.Flags != m_lastAgentUpdateArgs.Flags) || - (x.State != m_lastAgentUpdateArgs.State) || - (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || - (x.SessionID != m_lastAgentUpdateArgs.SessionID) || - (x.AgentID != m_lastAgentUpdateArgs.AgentID) + (vdelta1 > VDELTA) || + (vdelta2 > VDELTA) || + (vdelta3 > VDELTA) || + (vdelta4 > VDELTA) ) { //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", // x.CameraAtAxis, x.CameraCenter); //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", // x.CameraLeftAxis, x.CameraUpAxis); - //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", - // x.BodyRotation, x.HeadRotation); - //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", - // x.ControlFlags, x.Flags, x.Far, x.State); - - m_lastAgentUpdateArgs.AgentID = x.AgentID; - m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; - m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; - m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; - m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; - m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; - m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; - m_lastAgentUpdateArgs.Far = x.Far; - m_lastAgentUpdateArgs.Flags = x.Flags; - m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; - m_lastAgentUpdateArgs.SessionID = x.SessionID; - m_lastAgentUpdateArgs.State = x.State; - return true; } @@ -5629,75 +5652,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP } private bool HandleAgentUpdate(IClientAPI sener, Packet packet) - { - if (OnAgentUpdate != null) + { + // We got here, which means that something in agent update was significant + + AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; + AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; + + if (x.AgentID != AgentId || x.SessionID != SessionId) + return false; + + // Before we update the current m_thisAgentUpdateArgs, let's check this again + // to see what exactly changed + bool movement = CheckAgentMovementUpdateSignificance(x); + bool camera = CheckAgentCameraUpdateSignificance(x); + + m_thisAgentUpdateArgs.AgentID = x.AgentID; + m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; + m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; + m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; + m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; + m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; + m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; + m_thisAgentUpdateArgs.Far = x.Far; + m_thisAgentUpdateArgs.Flags = x.Flags; + m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; + m_thisAgentUpdateArgs.SessionID = x.SessionID; + m_thisAgentUpdateArgs.State = x.State; + + UpdateAgent handlerAgentUpdate = OnAgentUpdate; + UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; + UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; + + // Was there a significant movement/state change? + if (movement) { - AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; + if (handlerPreAgentUpdate != null) + OnPreAgentUpdate(this, m_thisAgentUpdateArgs); - // Now done earlier -// #region Packet Session and User Check -// if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) -// { -// PacketPool.Instance.ReturnPacket(packet); -// return false; -// } -// #endregion -// -// bool update = false; - AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; -// -// if (m_lastAgentUpdateArgs != null) -// { -// // These should be ordered from most-likely to -// // least likely to change. I've made an initial -// // guess at that. -// update = -// ( -// (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || -// (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || -// (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || -// (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || -// (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || -// (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || -// (x.Far != m_lastAgentUpdateArgs.Far) || -// (x.Flags != m_lastAgentUpdateArgs.Flags) || -// (x.State != m_lastAgentUpdateArgs.State) || -// (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || -// (x.SessionID != m_lastAgentUpdateArgs.SessionID) || -// (x.AgentID != m_lastAgentUpdateArgs.AgentID) -// ); -// } -// -// if (update) -// { -//// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); - - m_thisAgentUpdateArgs.AgentID = x.AgentID; - m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; - m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; - m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; - m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; - m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; - m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; - m_thisAgentUpdateArgs.Far = x.Far; - m_thisAgentUpdateArgs.Flags = x.Flags; - m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; - m_thisAgentUpdateArgs.SessionID = x.SessionID; - m_thisAgentUpdateArgs.State = x.State; - - UpdateAgent handlerAgentUpdate = OnAgentUpdate; - UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; - - if (handlerPreAgentUpdate != null) - OnPreAgentUpdate(this, m_thisAgentUpdateArgs); - - if (handlerAgentUpdate != null) - OnAgentUpdate(this, m_thisAgentUpdateArgs); - - handlerAgentUpdate = null; - handlerPreAgentUpdate = null; -// } + if (handlerAgentUpdate != null) + OnAgentUpdate(this, m_thisAgentUpdateArgs); } + // Was there a significant camera(s) change? + if (camera) + if (handlerAgentCameraUpdate != null) + handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); + + handlerAgentUpdate = null; + handlerPreAgentUpdate = null; + handlerAgentCameraUpdate = null; PacketPool.Instance.ReturnPacket(packet); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 990ef6e20b..55439645cd 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -801,6 +801,7 @@ namespace OpenSim.Region.Framework.Scenes { ControllingClient.OnCompleteMovementToRegion += CompleteMovement; ControllingClient.OnAgentUpdate += HandleAgentUpdate; + ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate; ControllingClient.OnAgentRequestSit += HandleAgentRequestSit; ControllingClient.OnAgentSit += HandleAgentSit; ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; @@ -1438,9 +1439,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", -// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); + //m_log.DebugFormat( + // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", + // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); if (IsChildAgent) { @@ -1448,10 +1449,6 @@ namespace OpenSim.Region.Framework.Scenes return; } - ++m_movementUpdateCount; - if (m_movementUpdateCount < 1) - m_movementUpdateCount = 1; - #region Sanity Checking // This is irritating. Really. @@ -1482,21 +1479,6 @@ namespace OpenSim.Region.Framework.Scenes AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; - // Camera location in world. We'll need to raytrace - // from this location from time to time. - CameraPosition = agentData.CameraCenter; - if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance) - { - ReprioritizeUpdates(); - m_lastCameraPosition = CameraPosition; - } - - // Use these three vectors to figure out what the agent is looking at - // Convert it to a Matrix and/or Quaternion - CameraAtAxis = agentData.CameraAtAxis; - CameraLeftAxis = agentData.CameraLeftAxis; - CameraUpAxis = agentData.CameraUpAxis; - // The Agent's Draw distance setting // When we get to the point of re-computing neighbors everytime this // changes, then start using the agent's drawdistance rather than the @@ -1504,12 +1486,6 @@ namespace OpenSim.Region.Framework.Scenes // DrawDistance = agentData.Far; DrawDistance = Scene.DefaultDrawDistance; - // Check if Client has camera in 'follow cam' or 'build' mode. - Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation); - - m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f) - && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; - m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; @@ -1529,17 +1505,6 @@ namespace OpenSim.Region.Framework.Scenes StandUp(); } - //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto); - // Raycast from the avatar's head to the camera to see if there's anything blocking the view - if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) - { - if (m_followCamAuto) - { - Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; - m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); - } - } - uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); @@ -1764,9 +1729,74 @@ namespace OpenSim.Region.Framework.Scenes } m_scene.EventManager.TriggerOnClientMovement(this); - TriggerScenePresenceUpdated(); } + + /// + /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering. + /// + public void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) + { + //m_log.DebugFormat( + // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}", + // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); + + if (IsChildAgent) + { + // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); + return; + } + + ++m_movementUpdateCount; + if (m_movementUpdateCount < 1) + m_movementUpdateCount = 1; + + + AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; + + // Camera location in world. We'll need to raytrace + // from this location from time to time. + CameraPosition = agentData.CameraCenter; + if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance) + { + ReprioritizeUpdates(); + m_lastCameraPosition = CameraPosition; + } + + // Use these three vectors to figure out what the agent is looking at + // Convert it to a Matrix and/or Quaternion + CameraAtAxis = agentData.CameraAtAxis; + CameraLeftAxis = agentData.CameraLeftAxis; + CameraUpAxis = agentData.CameraUpAxis; + + // The Agent's Draw distance setting + // When we get to the point of re-computing neighbors everytime this + // changes, then start using the agent's drawdistance rather than the + // region's draw distance. + // DrawDistance = agentData.Far; + DrawDistance = Scene.DefaultDrawDistance; + + // Check if Client has camera in 'follow cam' or 'build' mode. + Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation); + + m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f) + && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; + + + //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto); + // Raycast from the avatar's head to the camera to see if there's anything blocking the view + if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) + { + if (m_followCamAuto) + { + Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; + m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); + } + } + + TriggerScenePresenceUpdated(); + } + /// /// Calculate an update to move the presence to the set target. /// diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 3726191fbb..9b69da30df 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -687,6 +687,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 592e4e117c..6c38b6542e 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -258,6 +258,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 2fc3f0b3c8..5d7349a96e 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -106,6 +106,7 @@ namespace OpenSim.Tests.Common.Mock public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest;