public void TestCrossOnSameSimulator() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); // TestEventQueueGetModule eqmA = new TestEventQueueGetModule(); EntityTransferModule etmA = new EntityTransferModule(); EntityTransferModule etmB = new EntityTransferModule(); LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); IConfigSource config = new IniConfigSource(); IConfig modulesConfig = config.AddConfig("Modules"); modulesConfig.Set("EntityTransferModule", etmA.Name); modulesConfig.Set("SimulationServices", lscm.Name); // IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); // In order to run a single threaded regression test we do not want the entity transfer module waiting // for a callback from the destination scene before removing its avatar data. // entityTransferConfig.Set("wait_for_callback", false); SceneHelpers sh = new SceneHelpers(); TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); // SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA); SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); TestClient tc = new TestClient(acd, sceneA); List<TestClient> destinationTestClients = new List<TestClient>(); EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); originalSp.AbsolutePosition = new Vector3(128, 32, 10); // originalSp.Flying = true; // Console.WriteLine("First pos {0}", originalSp.AbsolutePosition); // eqmA.ClearEvents(); AgentUpdateArgs moveArgs = new AgentUpdateArgs(); //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; moveArgs.SessionID = acd.SessionID; originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); sceneA.Update(1); // Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. // But really we want to do this in a more robust way. for (int i = 0; i < 100; i++) { sceneA.Update(1); // Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); } // Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm // messages // Dictionary<UUID, List<TestEventQueueGetModule.Event>> eqmEvents = eqmA.Events; // // Assert.That(eqmEvents.Count, Is.EqualTo(1)); // Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True); // // List<TestEventQueueGetModule.Event> spEqmEvents = eqmEvents[originalSp.UUID]; // // Assert.That(spEqmEvents.Count, Is.EqualTo(1)); // Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion")); // sceneA should now only have a child agent ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True); ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); // Agent remains a child until the client triggers complete movement Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); int agentMovementCompleteReceived = 0; sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; sceneBTc.CompleteMovement(); Assert.That(agentMovementCompleteReceived, Is.EqualTo(1)); Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { bool recoverPhysActor = false; if (m_isChildAgent) { //m_log.Warn("[CROSSING]: HandleAgentUpdate from child agent ignored "+agentData.AgentID.ToString()); return; } if (IsInTransit) { // m_log.Error("[CROSSING]: AgentUpdate called during transit! Ignored."); return; } SceneObjectPart part = m_posInfo.Parent; EntityBase.PositionInfo posInfo = GetPosInfo(); if (part != null) { // sitting on a prim if (part.ParentGroup.InTransit) { // m_log.Warn("[CROSSING]: AgentUpdate called during prim transit! Ignored."); return; } } if (!posInfo.Position.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[SCENE PRESENCE]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error# 9999902"); if (m_LastFinitePos.IsFinite()) { SetAgentPositionInfo(false, m_LastFinitePos, posInfo.Parent, Vector3.Zero, Vector3.Zero); } else { Vector3 emergencyPos = new Vector3(127.0f, 127.0f, 127.0f); SetAgentPositionInfo(false, emergencyPos, posInfo.Parent, Vector3.Zero, Vector3.Zero); m_log.Error("[SCENE PRESENCE]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error# 9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_posInfo.Position; } m_perfMonMS = Environment.TickCount; uint flags = agentData.ControlFlags; Quaternion bodyRotation = agentData.BodyRotation; // Camera location in world. We'll need to raytrace // from this location from time to time. bool doCullingCheck = false; bool update_rotation = false; if (m_sceneView != null && m_sceneView.UseCulling) { if (!m_sceneView.NeedsFullSceneUpdate && (Environment.TickCount - m_lastCullCheckMS) > 0 && Vector3.DistanceSquared(agentData.CameraCenter, m_lastCameraCenter) > m_sceneView.DistanceBeforeCullingRequired * m_sceneView.DistanceBeforeCullingRequired) { //Check for new entities that we may now be able to see with this camera movement m_lastCameraCenter = agentData.CameraCenter; doCullingCheck = true; } else if (!m_sceneView.NeedsFullSceneUpdate && agentData.Far > m_DrawDistance) { //Check to see if the draw distance has gone up doCullingCheck = true; } //Do a culling check, if required if (doCullingCheck) { m_sceneView.CheckForDistantEntitiesToShow(); //Also tell all child regions about the change SendChildAgentUpdate(); m_lastCullCheckMS = Environment.TickCount + 1000;//Only do the camera check at the most once a sec } } m_CameraCenter = agentData.CameraCenter; // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion m_CameraAtAxis = agentData.CameraAtAxis; m_CameraLeftAxis = agentData.CameraLeftAxis; m_CameraUpAxis = agentData.CameraUpAxis; // check if the Agent's Draw distance setting has changed if (m_DrawDistance != agentData.Far) { m_DrawDistance = agentData.Far; m_remotePresences.HandleDrawDistanceChanged((uint)agentData.Far); } if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(false, true); bodyRotation = m_bodyRot; // if standing, preserve the current rotation update_rotation = true; } m_mouseLook = (flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; lock (m_scriptedcontrols) { if (m_scriptedcontrols.Count > 0) { SendControlToScripts(flags); flags = RemoveIgnoredControls(flags, IgnoredControls); } } PhysicsActor physActor = PhysicsActor; m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; m_state = (AgentState)agentData.State; if (physActor == null) { Velocity = Vector3.Zero; return; } if (m_autopilotMoving) CheckAtSitTarget(); if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) { m_animPersistUntil = 0; // abort any timed animation TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); m_sittingGround = true; } // In the future, these values might need to go global. // Here's where you get them. if (m_allowMovement) { bool update_movementflag = false; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; // Update the physactor's rotation. This communicates the rotation to the character controller. physActor.Rotation = bodyRotation; bool oldflying = physActor.Flying; if (m_forceFly) physActor.Flying = true; else if (m_flyDisabled) physActor.Flying = false; else physActor.Flying = ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (physActor.Flying != oldflying) { update_movementflag = true; if (physActor.Flying && physActor.CollidingGround) { physActor.AddForce(new Vector3(0f, 0f, FLY_LAUNCH_FORCE) * physActor.Mass, ForceType.GlobalLinearImpulse); } } if (bodyRotation != m_bodyRot) { m_bodyRot = bodyRotation; update_rotation = true; } if (m_posInfo.Parent != null) { // abort any automated movement m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; } else { bool bAllowUpdateMoveToPosition = false; bool bResetMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if ((m_mouseLook || m_leftButtonDown) && !physActor.Flying) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; bool nudgeStarted = false; for (int i=0; i<Dir_Flags.Length; ++i) { Dir_ControlFlags DCF = Dir_Flags[i]; if ((flags & (uint) DCF) != 0) { bResetMoveToPosition = true; DCFlagKeyPressed = true; agent_control_v3 += dirVectors[i]; if ((m_movementflag & (uint) DCF) == 0) { m_movementflag += (uint)DCF & PrimaryMovements; // This is an abomination. update_movementflag = true; // The viewers do not send up or down nudges. if ((DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE) != 0 || (DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_REVERSE_NUDGE) != 0 || (DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN_NUDGE) != 0 || (DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE) != 0 || (DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) != 0 ) { //when we start a nudge, we let it run for a period of time and then cancel the force _nudgeStart = (uint)Environment.TickCount; if ((DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE) != 0 || (DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) != 0) _nudgeDuration = NUDGE_DURATION_LR; else _nudgeDuration = NUDGE_DURATION_AT; nudgeStarted = true; } else { if (!nudgeStarted) _nudgeStart = 0; } if (((DCF & Dir_ControlFlags.DIR_CONTROL_FLAG_UP) != 0) && physActor.CollidingGround && !physActor.Flying) { //begin a jump physActor.AddForce(new Vector3(0.0f, 0.0f, JUMP_FORCE) * physActor.Mass, ForceType.LocalLinearImpulse); } } } else { if ((m_movementflag & (uint) DCF) != 0) { m_movementflag -= (uint) DCF & PrimaryMovements; // This is an abomination. update_movementflag = true; if (!nudgeStarted) _nudgeStart = 0; } else { bAllowUpdateMoveToPosition = true; } } } //Paupaw:Do Proper PID for Autopilot here if (bResetMoveToPosition) { m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; bAllowUpdateMoveToPosition = false; } if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving)) { //Check the error term of the current position in relation to the target position if (IsAtTarget(m_moveToPositionTarget)) { // we are close enough to the target m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; } else { try { // move avatar in 3D at one meter/second towards target, in avatar coordinate frame. // This movement vector gets added to the velocity through AddNewMovement(). // Theoretically we might need a more complex PID approach here if other // unknown forces are acting on the avatar and we need to adaptively respond // to such forces, but the following simple approach seems to works fine. Vector3 LocalVectorToTarget = (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords LocalVectorToTarget.Normalize(); agent_control_v3 += LocalVectorToTarget; Vector3 movementPush = (m_moveToPositionTarget - AbsolutePosition); movementPush.Normalize(); movementPush.Z *= physActor.Mass; if (physActor.IsColliding) movementPush.Z *= FLY_LAUNCH_FORCE; physActor.AddForce(movementPush, ForceType.GlobalLinearImpulse); // update avatar movement flags. the avatar coordinate system is as follows: // // +X (forward) // // ^ // | // | // | // | // (left) +Y <--------o--------> -Y // avatar // | // | // | // | // v // -X // // based on the above avatar coordinate system, classify the movement into // one of left/right/back/forward. if (LocalVectorToTarget.Y > 0)//MoveLeft { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; update_movementflag = true; } else if (LocalVectorToTarget.Y < 0) //MoveRight { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; update_movementflag = true; } if (LocalVectorToTarget.X < 0) //MoveBack { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; update_movementflag = true; } else if (LocalVectorToTarget.X > 0) //Move Forward { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; update_movementflag = true; } if (LocalVectorToTarget.Z > 0) //Up { // Don't set these flags for up - doing so will make the avatar // keep trying to jump even if walking along level ground. // m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; update_movementflag = true; } else if (LocalVectorToTarget.Z < 0) //Down { // Don't set these flags for down - doing so will make the avatar crouch. // m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; update_movementflag = true; } } catch (Exception) { //Avoid system crash, can be slower but... } } } // Determine whether the user has said to stop and the agent is not sitting. physActor.SetAirBrakes = (m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_STOP) != 0 && !IsInTransitOnPrim && !m_moveToPositionInProgress; } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (physActor != null && physActor.Flying && !m_forceFly) { // Are the landing controls requirements filled? bool controlland = (((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); // Are the collision requirements fulfilled? bool colliding = (physActor.CollidingGround == true); if (physActor.Flying && colliding && controlland) { StopFlying(); } } if (m_newPhysActorNeedsUpdate && physActor != null) update_movementflag = true; if (!m_sittingGround && (update_movementflag || (update_rotation && DCFlagKeyPressed))) { AddNewMovement(agent_control_v3, bodyRotation); if (update_movementflag) UpdateMovementAnimations(); if (physActor != null) m_newPhysActorNeedsUpdate = false; } else if (update_rotation) { //avatar is spinning with no other changes // m_log.WarnFormat("[SP]: HandleAgentUpdate: Sending terse update vel={0}",this.Velocity); SendTerseUpdateToAllClients(); } } m_scene.EventManager.TriggerOnClientMovement(this); m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //if (m_isChildAgent) //{ // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); // return; //} m_perfMonMS = Util.EnvironmentTickCount(); ++m_movementUpdateCount; if (m_movementUpdateCount < 1) m_movementUpdateCount = 1; #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; if (!m_pos.IsFinite()) { m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_pos; } #endregion Sanity Checking #region Inputs AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; Quaternion bodyRotation = agentData.BodyRotation; // Camera location in world. We'll need to raytrace // from this location from time to time. m_CameraCenter = agentData.CameraCenter; if (Vector3.Distance(m_lastCameraCenter, m_CameraCenter) >= Scene.RootReprioritizationDistance) { ReprioritizeUpdates(); m_lastCameraCenter = m_CameraCenter; } // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion m_CameraAtAxis = agentData.CameraAtAxis; m_CameraLeftAxis = agentData.CameraLeftAxis; m_CameraUpAxis = agentData.CameraUpAxis; // The Agent's Draw distance setting m_DrawDistance = agentData.Far; // Check if Client has camera in 'follow cam' or 'build' mode. Vector3 camdif = (Vector3.One * m_bodyRot - Vector3.One * CameraRotation); m_followCamAuto = ((m_CameraUpAxis.Z > 0.959f && m_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; #endregion Inputs if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { 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(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); } } lock (scriptedcontrols) { if (scriptedcontrols.Count > 0) { SendControlToScripts((uint)flags); flags = RemoveIgnoredControls(flags, IgnoredControls); } } if (m_autopilotMoving) CheckAtSitTarget(); if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) { // TODO: This doesn't prevent the user from walking yet. // Setting parent ID would fix this, if we knew what value // to use. Or we could add a m_isSitting variable. //Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); SitGround = true; } // In the future, these values might need to go global. // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; m_state = agentData.State; PhysicsActor actor = PhysicsActor; if (actor == null) { return; } bool update_movementflag = false; if (m_allowMovement) { if (agentData.UseClientAgentPosition) { m_moveToPositionInProgress = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; m_moveToPositionTarget = agentData.ClientAgentPosition; } int i = 0; bool update_rotation = false; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; Quaternion q = bodyRotation; bool oldflying = PhysicsActor.Flying; if (m_forceFly) actor.Flying = true; else if (m_flyDisabled) actor.Flying = false; else actor.Flying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != oldflying) update_movementflag = true; if (q != m_bodyRot) { m_bodyRot = q; update_rotation = true; } if (m_parentID == 0) { bool bAllowUpdateMoveToPosition = false; bool bResetMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if ((m_mouseLook && !m_physicsActor.Flying) || (m_leftButtonDown && !m_physicsActor.Flying)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; // The fact that m_movementflag is a byte needs to be fixed // it really should be a uint uint nudgehack = 250; foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { if (((uint)flags & (uint)DCF) != 0) { bResetMoveToPosition = true; DCFlagKeyPressed = true; try { agent_control_v3 += dirVectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) { // Why did I get this? } if ((m_movementflag & (byte)(uint)DCF) == 0) { if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) { m_movementflag |= (byte)nudgehack; } m_movementflag += (byte)(uint)DCF; update_movementflag = true; } } else { if ((m_movementflag & (byte)(uint)DCF) != 0 || ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((m_movementflag & (byte)nudgehack) == nudgehack)) ) // This or is for Nudge forward { m_movementflag -= ((byte)(uint)DCF); update_movementflag = true; /* if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((m_movementflag & (byte)nudgehack) == nudgehack)) { m_log.Debug("Removed Hack flag"); } */ } else { bAllowUpdateMoveToPosition = true; } } i++; } //Paupaw:Do Proper PID for Autopilot here if (bResetMoveToPosition) { m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; bAllowUpdateMoveToPosition = false; } if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving)) { //Check the error term of the current position in relation to the target position if (Util.GetDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 0.5f) { // we are close enough to the target m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; } else { try { // move avatar in 2D at one meter/second towards target, in avatar coordinate frame. // This movement vector gets added to the velocity through AddNewMovement(). // Theoretically we might need a more complex PID approach here if other // unknown forces are acting on the avatar and we need to adaptively respond // to such forces, but the following simple approach seems to works fine. Vector3 LocalVectorToTarget3D = (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords // Ignore z component of vector Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); LocalVectorToTarget2D.Normalize(); agent_control_v3 += LocalVectorToTarget2D; // update avatar movement flags. the avatar coordinate system is as follows: // // +X (forward) // // ^ // | // | // | // | // (left) +Y <--------o--------> -Y // avatar // | // | // | // | // v // -X // // based on the above avatar coordinate system, classify the movement into // one of left/right/back/forward. if (LocalVectorToTarget2D.Y > 0)//MoveLeft { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; //AgentControlFlags AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; update_movementflag = true; } else if (LocalVectorToTarget2D.Y < 0) //MoveRight { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; update_movementflag = true; } if (LocalVectorToTarget2D.X < 0) //MoveBack { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; update_movementflag = true; } else if (LocalVectorToTarget2D.X > 0) //Move Forward { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; update_movementflag = true; } } catch (Exception e) { //Avoid system crash, can be slower but... m_log.DebugFormat("Crash! {0}", e.ToString()); } } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (m_physicsActor != null && m_physicsActor.Flying && !m_forceFly) { // Landing detection code // Are the landing controls requirements filled? bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); // Are the collision requirements fulfilled? bool colliding = (m_physicsActor.IsColliding == true); if (m_physicsActor.Flying && colliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't // want to do it every step when flying. if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) StopFlying(); } } if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { // m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); // m_log.DebugFormat( // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); AddNewMovement(agent_control_v3, q); } } if (update_movementflag && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) == 0) && (m_parentID == 0) && !SitGround) Animator.UpdateMovementAnimations(); m_scene.EventManager.TriggerOnClientMovement(this); m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); }
void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //If we are forcing a position for them to go if (forcedPosition.ContainsKey(remoteClient.AgentId)) { ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId); //Putting the user into flying, both keeps the avatar in fligth when it bumps into something and stopped from going another direction AND //When the avatar walks into a ban line on the ground, it prevents getting stuck agentData.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; //Make sure we stop if they get about to the right place to prevent yoyo and prevents getting stuck on banlines if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) < .2) { // m_log.DebugFormat( // "[LAND MANAGEMENT MODULE]: Stopping force position of {0} because {1} is close enough to {2}", // clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]); forcedPosition.Remove(remoteClient.AgentId); } //if we are far away, teleport else if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) > 3) { Vector3 forcePosition = forcedPosition[remoteClient.AgentId]; // m_log.DebugFormat( // "[LAND MANAGEMENT MODULE]: Teleporting out {0} because {1} is too far from avatar position {2}", // clientAvatar.Name, clientAvatar.AbsolutePosition, forcePosition); m_scene.RequestTeleportLocation(remoteClient, m_scene.RegionInfo.RegionHandle, forcePosition, clientAvatar.Lookat, (uint)Constants.TeleportFlags.ForceRedirect); forcedPosition.Remove(remoteClient.AgentId); } else { // m_log.DebugFormat( // "[LAND MANAGEMENT MODULE]: Forcing {0} from {1} to {2}", // clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]); //Forces them toward the forced position we want if they aren't there yet agentData.UseClientAgentPosition = true; agentData.ClientAgentPosition = forcedPosition[remoteClient.AgentId]; } } }
public void FilterAgentUpdate(IClientAPI remoteClient, OpenMetaverse.Packets.AgentUpdatePacket.AgentDataBlock x) { bool update; if (m_lastAgentUpdate != null) { // These should be ordered from most-likely to // least likely to change. I've made an initial // guess at that. update = ( (m_moveToPositionInProgress) || (Util.NotEquals(x.BodyRotation, m_lastAgentUpdate.BodyRotation, Util.DefaultComparePrecision)) || (Util.NotEquals(x.CameraAtAxis, m_lastAgentUpdate.CameraAtAxis, Util.DefaultComparePrecision)) || (Util.NotEquals(x.CameraCenter, m_lastAgentUpdate.CameraCenter, Util.DefaultComparePrecision)) || (Util.NotEquals(x.CameraLeftAxis, m_lastAgentUpdate.CameraLeftAxis, Util.DefaultComparePrecision)) || (Util.NotEquals(x.CameraUpAxis, m_lastAgentUpdate.CameraUpAxis, Util.DefaultComparePrecision)) || (x.ControlFlags != m_lastAgentUpdate.ControlFlags) || (Util.NotEquals(x.Far, m_lastAgentUpdate.Far, Util.DefaultComparePrecision)) || (x.Flags != m_lastAgentUpdate.Flags) || (x.State != m_lastAgentUpdate.State) || (Util.NotEquals(x.HeadRotation, m_lastAgentUpdate.HeadRotation, Util.DefaultComparePrecision)) || (x.SessionID != m_lastAgentUpdate.SessionID) || (x.AgentID != m_lastAgentUpdate.AgentID) ); } else { update = true; } if (update) { // m_log.WarnFormat("[SCENE PRESENCE]: AgentUpdate: {0} {1} {2} {3} {4}", this.Name, x.Flags.ToString("X2"), x.ControlFlags.ToString("X8"), x.State.ToString(), this.Velocity.ToString()); AgentUpdateArgs arg = new AgentUpdateArgs(); arg.AgentID = x.AgentID; arg.BodyRotation = x.BodyRotation; arg.CameraAtAxis = x.CameraAtAxis; arg.CameraCenter = x.CameraCenter; arg.CameraLeftAxis = x.CameraLeftAxis; arg.CameraUpAxis = x.CameraUpAxis; arg.ControlFlags = x.ControlFlags; arg.Far = x.Far; arg.Flags = x.Flags; arg.HeadRotation = x.HeadRotation; arg.SessionID = x.SessionID; arg.State = x.State; m_lastAgentUpdate = arg; // save this set of arguments for nexttime HandleAgentUpdate(remoteClient, arg); } }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { // m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", // Scene.Name, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); if (IsChildAgent) { // m_log.DebugFormat("DEBUG: HandleAgentUpdate: child agent in {0}", Scene.Name); return; } if (IsInTransit) return; #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; if (!m_pos.IsFinite()) { m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_pos; } #endregion Sanity Checking #region Inputs AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; // 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; m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; // FIXME: This does not work as intended because the viewer only sends the lbutton down when the button // is first pressed, not whilst it is held down. If this is required in the future then need to look // for an AGENT_CONTROL_LBUTTON_UP event and make sure to handle cases where an initial DOWN is not // received (e.g. on holding LMB down on the avatar in a viewer). m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; #endregion Inputs // // Make anims work for client side autopilot // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0) // m_updateCount = UPDATE_COUNT; // // // Make turning in place work // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0 || // (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) // m_updateCount = UPDATE_COUNT; if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); } // Raycast from the avatar's head to the camera to see if there's anything blocking the view // this exclude checks may not be complete if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast()) { if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0) { Vector3 posAdjusted = AbsolutePosition; // posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f; posAdjusted.Z += 1.0f; // viewer current camera focus point Vector3 tocam = CameraPosition - posAdjusted; tocam.X = (float)Math.Round(tocam.X, 1); tocam.Y = (float)Math.Round(tocam.Y, 1); tocam.Z = (float)Math.Round(tocam.Z, 1); float distTocamlen = tocam.Length(); if (distTocamlen > 0.3f) { tocam *= (1.0f / distTocamlen); posAdjusted.X = (float)Math.Round(posAdjusted.X, 1); posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1); posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1); m_doingCamRayCast = true; m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); } } else if (CameraConstraintActive && (m_mouseLook || ParentID != 0)) { Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... UpdateCameraCollisionPlane(plane); CameraConstraintActive = false; } } uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) HandleAgentSitOnGround(); // In the future, these values might need to go global. // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; byte oldState = State; State = agentData.State; // We need to send this back to the client in order to stop the edit beams if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None) SendAgentTerseUpdate(this); PhysicsActor actor = PhysicsActor; // This will be the case if the agent is sitting on the groudn or on an object. if (actor == null) { SendControlsToScripts(flagsForScripts); return; } if (AllowMovement && !SitGround) { // m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name); bool update_rotation = false; if (agentData.BodyRotation != Rotation) { Rotation = agentData.BodyRotation; update_rotation = true; } bool update_movementflag = false; if (agentData.UseClientAgentPosition) { MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; MoveToPositionTarget = agentData.ClientAgentPosition; } int i = 0; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; bool newFlying = false; if (ForceFly) newFlying = true; else if (FlyDisabled) newFlying = false; else newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != newFlying) { // Note: ScenePresence.Flying is actually fetched from the physical actor // so setting PhysActor.Flying here also sets the ScenePresence's value. actor.Flying = newFlying; update_movementflag = true; } if (ParentID == 0) { bool bAllowUpdateMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. // if (!Flying && (m_mouseLook || m_leftButtonDown)) // dirVectors = GetWalkDirectionVectors(); // else dirVectors = Dir_Vectors; // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { if (((uint)flags & (uint)DCF) != 0) { DCFlagKeyPressed = true; try { agent_control_v3 += Dir_Vectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) { // Why did I get this? } if (((MovementFlag & (uint)DCF) == 0)) { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); MovementFlag |= (uint)DCF; update_movementflag = true; } } else { if ((MovementFlag & (uint)DCF) != 0) { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); MovementFlag &= (uint)~DCF; update_movementflag = true; /* if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((MovementFlag & (byte)nudgehack) == nudgehack)) { m_log.Debug("Removed Hack flag"); } */ } else { bAllowUpdateMoveToPosition = true; } } i++; } // Detect AGENT_CONTROL_STOP state changes if (AgentControlStopActive != ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STOP) != 0)) { AgentControlStopActive = !AgentControlStopActive; update_movementflag = true; } if (MovingToTarget) { // If the user has pressed a key then we want to cancel any move to target. if (DCFlagKeyPressed) { ResetMoveToTarget(); update_movementflag = true; } else if (bAllowUpdateMoveToPosition) { // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a // certain position. It's only check for tolerance on returning to that position is 0.2 // rather than 1, at which point it removes its force target. if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2 : 1, ref agent_control_v3)) update_movementflag = true; } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (Flying && !ForceFly) { // Need to stop in mid air if user holds down AGENT_CONTROL_STOP // if (AgentControlStopActive) // { // agent_control_v3 = Vector3.Zero; // } // else { // Landing detection code // Are the landing controls requirements filled? bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); //m_log.Debug("[CONTROL]: " +flags); // Applies a satisfying roll effect to the avatar when flying. if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) { ApplyFlyingRoll( FLY_ROLL_RADIANS_PER_UPDATE, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) { ApplyFlyingRoll( -FLY_ROLL_RADIANS_PER_UPDATE, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } else { if (m_AngularVelocity.Z != 0) m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); } /* if (Flying && IsColliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't // want to do it every step when flying. if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) StopFlying(); } */ } } else if (IsColliding && agent_control_v3.Z < 0f) agent_control_v3.Z = 0; // else if(AgentControlStopActive %% Velocity.Z <0.01f) // m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); // If the agent update does move the avatar, then calculate the force ready for the velocity update, // which occurs later in the main scene loop // We also need to update if the user rotates their avatar whilst it is slow walking/running (if they // held down AGENT_CONTROL_STOP whilst normal walking/running). However, we do not want to update // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the // avatar location in place). if (update_movementflag || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0))) { if (AgentControlStopActive) { // if (MovementFlag == 0 && Animator.Falling) if (MovementFlag == 0 && Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling) { AddNewMovement(agent_control_v3, AgentControlStopSlowVel, true); } else AddNewMovement(agent_control_v3, AgentControlStopSlowVel); } else { AddNewMovement(agent_control_v3); } } if (update_movementflag && ParentID == 0) { // m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name); Animator.UpdateMovementAnimations(); } SendControlsToScripts(flagsForScripts); } // We need to send this back to the client in order to see the edit beams if ((State & (uint)AgentState.Editing) != 0) SendAgentTerseUpdate(this); m_scene.EventManager.TriggerOnClientMovement(this); }
public void OnBotAgentUpdate(ScenePresence presence, Vector3 toward, uint controlFlag, Quaternion bodyRotation, bool isMoving) { if (m_controller.Bot.Frozen && isMoving) { var pa = presence.PhysicsActor; bool fly = pa != null && pa.Flying; StopMoving(presence, fly, false); return; } if (isMoving) m_hasStoppedMoving = false; AgentUpdateArgs pack = new AgentUpdateArgs { ControlFlags = controlFlag, BodyRotation = bodyRotation }; presence.HandleAgentUpdate(presence.ControllingClient, pack); }
private void RealHandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //if (m_isChildAgent) //{ // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); // return; //} m_movementUpdateCount++; if (m_movementUpdateCount >= int.MaxValue) m_movementUpdateCount = 1; // Must check for standing up even when PhysicsActor is null, // since sitting currently removes avatar from physical scene //m_log.Debug("agentPos:" + AbsolutePosition.ToString()); // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error# 9999902"); m_pos = m_LastFinitePos; if (!m_pos.IsFinite()) { m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error# 9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_pos; } //m_physicsActor.AddForce(new PhysicsVector(999999999, 99999999, 999999999999999), true); //ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); //if (land != null) //{ //if (land.landData.landingType == (byte)1 && land.landData.userLocation != Vector3.Zero) //{ // agent.startpos = land.landData.userLocation; //} //} m_perfMonMS = Environment.TickCount; uint flags = agentData.ControlFlags; Quaternion bodyRotation = agentData.BodyRotation; // Camera location in world. We'll need to raytrace // from this location from time to time. m_CameraCenter = agentData.CameraCenter; // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion m_CameraAtAxis = agentData.CameraAtAxis; m_CameraLeftAxis = agentData.CameraLeftAxis; m_CameraUpAxis = agentData.CameraUpAxis; // The Agent's Draw distance setting m_DrawDistance = agentData.Far; if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); } // Check if Client has camera in 'follow cam' or 'build' mode. Vector3 camdif = (Vector3.One * m_bodyRot - Vector3.One * CameraRotation); m_followCamAuto = ((m_CameraUpAxis.Z > 0.959f && m_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 headadjustment = new Vector3(0, 0, 0.3f); m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - (m_pos + headadjustment)), Vector3.Distance(m_CameraCenter, (m_pos + headadjustment)) + 0.3f, RayCastCameraCallback); } } m_mouseLook = (flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; lock (scriptedcontrols) { if (scriptedcontrols.Count > 0) { SendControlToScripts(flags); flags = RemoveIgnoredControls(flags, IgnoredControls); } } if (PhysicsActor == null) { return; } if (m_autopilotMoving) CheckAtSitTarget(); if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) { // TODO: This doesn't prevent the user from walking yet. // Setting parent ID would fix this, if we knew what value // to use. Or we could add a m_isSitting variable. TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); } // In the future, these values might need to go global. // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; m_state = agentData.State; if (m_allowMovement) { int i = 0; bool update_movementflag = false; bool update_rotation = false; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = new Vector3(0, 0, 0); Quaternion q = bodyRotation; if (PhysicsActor != null) { bool oldflying = PhysicsActor.Flying; if (m_forceFly) PhysicsActor.Flying = true; else if (m_flyDisabled) PhysicsActor.Flying = false; else PhysicsActor.Flying = ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (PhysicsActor.Flying != oldflying) { update_movementflag = true; } } if (q != m_bodyRot) { m_bodyRot = q; update_rotation = true; } if (m_parentID == 0) { bool bAllowUpdateMoveToPosition = false; bool bResetMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if ((m_mouseLook && !m_physicsActor.Flying) || (m_leftButtonDown && !m_physicsActor.Flying)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; foreach (Dir_ControlFlags DCF in Enum.GetValues(typeof (Dir_ControlFlags))) { if ((flags & (uint) DCF) != 0) { bResetMoveToPosition = true; DCFlagKeyPressed = true; try { agent_control_v3 += dirVectors[i]; } catch (IndexOutOfRangeException) { // Why did I get this? } if ((m_movementflag & (uint) DCF) == 0) { m_movementflag += (byte) (uint) DCF; update_movementflag = true; } } else { if ((m_movementflag & (uint) DCF) != 0) { m_movementflag -= (byte) (uint) DCF; update_movementflag = true; } else { bAllowUpdateMoveToPosition = true; } } i++; } //Paupaw:Do Proper PID for Autopilot here if (bResetMoveToPosition) { m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; bAllowUpdateMoveToPosition = false; } if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving)) { //Check the error term of the current position in relation to the target position if (Util.GetDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 1.5) { // we are close enough to the target m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; } else { try { // move avatar in 2D at one meter/second towards target, in avatar coordinate frame. // This movement vector gets added to the velocity through AddNewMovement(). // Theoretically we might need a more complex PID approach here if other // unknown forces are acting on the avatar and we need to adaptively respond // to such forces, but the following simple approach seems to works fine. Vector3 LocalVectorToTarget3D = (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords // Ignore z component of vector Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); LocalVectorToTarget2D.Normalize(); agent_control_v3 += LocalVectorToTarget2D; // update avatar movement flags. the avatar coordinate system is as follows: // // +X (forward) // // ^ // | // | // | // | // (left) +Y <--------o--------> -Y // avatar // | // | // | // | // v // -X // // based on the above avatar coordinate system, classify the movement into // one of left/right/back/forward. if (LocalVectorToTarget2D.Y > 0)//MoveLeft { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; update_movementflag = true; } else if (LocalVectorToTarget2D.Y < 0) //MoveRight { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; update_movementflag = true; } if (LocalVectorToTarget2D.X < 0) //MoveBack { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; update_movementflag = true; } else if (LocalVectorToTarget2D.X > 0) //Move Forward { m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; update_movementflag = true; } } catch (Exception) { //Avoid system crash, can be slower but... } } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (m_physicsActor != null && m_physicsActor.Flying && !m_forceFly) { // Are the landing controls requirements filled? bool controlland = (((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); // Are the collision requirements fulfilled? bool colliding = (m_physicsActor.IsColliding == true); if (m_physicsActor.Flying && colliding && controlland) { StopFlying(); } } if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { // m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); // m_log.DebugFormat( // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); AddNewMovement(agent_control_v3, q); if (update_movementflag) UpdateMovementAnimations(); } } m_scene.EventManager.TriggerOnClientMovement(this); m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> 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); if (IsChildAgent) { // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); return; } #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; if (!m_pos.IsFinite()) { m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_pos; } #endregion Sanity Checking #region Inputs AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; // 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; m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; #endregion Inputs // // Make anims work for client side autopilot // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0) // m_updateCount = UPDATE_COUNT; // // // Make turning in place work // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0 || // (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) // m_updateCount = UPDATE_COUNT; if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); } uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) HandleAgentSitOnGround(); // In the future, these values might need to go global. // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; byte oldState = State; State = agentData.State; // We need to send this back to the client in order to stop the edit beams if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None) ControllingClient.SendAgentTerseUpdate(this); PhysicsActor actor = PhysicsActor; if (actor == null) { SendControlsToScripts(flagsForScripts); return; } if (AllowMovement && !SitGround) { Quaternion bodyRotation = agentData.BodyRotation; bool update_rotation = false; if (bodyRotation != Rotation) { Rotation = bodyRotation; update_rotation = true; } bool update_movementflag = false; if (agentData.UseClientAgentPosition) { MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; MoveToPositionTarget = agentData.ClientAgentPosition; } int i = 0; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; bool newFlying = actor.Flying; if (ForceFly) newFlying = true; else if (FlyDisabled) newFlying = false; else newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != newFlying) { // Note: ScenePresence.Flying is actually fetched from the physical actor // so setting PhysActor.Flying here also sets the ScenePresence's value. actor.Flying = newFlying; update_movementflag = true; } if (ParentID == 0) { bool bAllowUpdateMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if (!Flying && (m_mouseLook || m_leftButtonDown)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; // The fact that MovementFlag is a byte needs to be fixed // it really should be a uint // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. uint nudgehack = 250; foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { if (((uint)flags & (uint)DCF) != 0) { DCFlagKeyPressed = true; try { agent_control_v3 += dirVectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) { // Why did I get this? } if ((MovementFlag & (byte)(uint)DCF) == 0) { if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) { MovementFlag |= (byte)nudgehack; } //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); MovementFlag += (byte)(uint)DCF; update_movementflag = true; } } else { if ((MovementFlag & (byte)(uint)DCF) != 0 || ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) && ((MovementFlag & (byte)nudgehack) == nudgehack)) ) // This or is for Nudge forward { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); MovementFlag -= ((byte)(uint)DCF); update_movementflag = true; /* if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((MovementFlag & (byte)nudgehack) == nudgehack)) { m_log.Debug("Removed Hack flag"); } */ } else { bAllowUpdateMoveToPosition = true; } } i++; } if (MovingToTarget) { // If the user has pressed a key then we want to cancel any move to target. if (DCFlagKeyPressed) { ResetMoveToTarget(); update_movementflag = true; } else if (bAllowUpdateMoveToPosition) { // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a // certain position. It's only check for tolerance on returning to that position is 0.2 // rather than 1, at which point it removes its force target. if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2 : 1, ref agent_control_v3)) update_movementflag = true; } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (Flying && !ForceFly) { // Landing detection code // Are the landing controls requirements filled? bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); //m_log.Debug("[CONTROL]: " +flags); // Applies a satisfying roll effect to the avatar when flying. if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) { ApplyFlyingRoll( FLY_ROLL_RADIANS_PER_UPDATE, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) { ApplyFlyingRoll( -FLY_ROLL_RADIANS_PER_UPDATE, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } else { if (m_AngularVelocity.Z != 0) m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); } if (Flying && IsColliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't // want to do it every step when flying. if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) StopFlying(); } } // If the agent update does move the avatar, then calculate the force ready for the velocity update, // which occurs later in the main scene loop if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { // m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, ur = {4}", // m_scene.RegionInfo.RegionName, agent_control_v3, Name, update_movementflag, update_rotation); AddNewMovement(agent_control_v3); } // else // { // if (!update_movementflag) // { // m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false", // m_scene.RegionInfo.RegionName, agent_control_v3, Name); // } // } if (update_movementflag && ParentID == 0) Animator.UpdateMovementAnimations(); SendControlsToScripts(flagsForScripts); } // We need to send this back to the client in order to see the edit beams if ((State & (uint)AgentState.Editing) != 0) ControllingClient.SendAgentTerseUpdate(this); m_scene.EventManager.TriggerOnClientMovement(this); }
public void TestCrossOnSameSimulatorNoRootDestPerm() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); EntityTransferModule etmA = new EntityTransferModule(); EntityTransferModule etmB = new EntityTransferModule(); LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); IConfigSource config = new IniConfigSource(); IConfig modulesConfig = config.AddConfig("Modules"); modulesConfig.Set("EntityTransferModule", etmA.Name); modulesConfig.Set("SimulationServices", lscm.Name); SceneHelpers sh = new SceneHelpers(); TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); // We need to set up the permisions module on scene B so that our later use of agent limit to deny // QueryAccess won't succeed anyway because administrators are always allowed in and the default // IsAdministrator if no permissions module is present is true. SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new DefaultPermissionsModule(), etmB); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); TestClient tc = new TestClient(acd, sceneA); List<TestClient> destinationTestClients = new List<TestClient>(); EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); // Make sure sceneB will not accept this avatar. sceneB.RegionInfo.EstateSettings.PublicAccess = false; ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); originalSp.AbsolutePosition = new Vector3(128, 32, 10); AgentUpdateArgs moveArgs = new AgentUpdateArgs(); //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; moveArgs.SessionID = acd.SessionID; originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); sceneA.Update(1); // Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. // But really we want to do this in a more robust way. for (int i = 0; i < 100; i++) { sceneA.Update(1); // Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); } // sceneA agent should still be root ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); Assert.That(spAfterCrossSceneA.IsChildAgent, Is.False); ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); // sceneB agent should still be child Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); // sceneB should ignore unauthorized attempt to upgrade agent to root TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); int agentMovementCompleteReceived = 0; sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; sceneBTc.CompleteMovement(); Assert.That(agentMovementCompleteReceived, Is.EqualTo(0)); Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { lock (m_agentUpdates) { if (m_updatesAllowed) { RealHandleAgentUpdate(remoteClient, agentData); return; } m_agentUpdates.Add(agentData); } }
void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //If we are forcing a position for them to go if (forcedPosition != null) { ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId); //Putting the user into flying, both keeps the avatar in fligth when it bumps into something and stopped from going another direction AND //When the avatar walks into a ban line on the ground, it prevents getting stuck agentData.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; //Make sure we stop if they get about to the right place to prevent yoyo and prevents getting stuck on banlines if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition.Value) < .2) { Debug.WriteLine(string.Format("Stopping force position because {0} is close enough to position {1}", forcedPosition.Value, clientAvatar.AbsolutePosition)); forcedPosition = null; } //if we are far away, teleport else if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition.Value) > 3) { Debug.WriteLine(string.Format("Teleporting out because {0} is too far from avatar position {1}", forcedPosition.Value, clientAvatar.AbsolutePosition)); clientAvatar.Teleport(forcedPosition.Value); forcedPosition = null; } else { //Forces them toward the forced position we want if they aren't there yet agentData.UseClientAgentPosition = true; agentData.ClientAgentPosition = forcedPosition.Value; } } }
void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { }
// Some presence property has changed. Generate a call into the scene presence // so the new values are evaluated (like AgentControlFlags). // The ScenePresence will trigger OnScenePresenceUpdated and we rely on the // fact that the values will all be equal to supress the generation of a // new outgoing property update message. private void GenerateAgentUpdated(ScenePresence sp) { // The call for the change of these values comes out of the client view // which has an OnAgentUpdate event that the scene presence connects to. // We can't use the OnAgentUpdate event subscription (we're not derived // from client view) so we fake the reception of a presenece changing // message by building up the parameter block and directly calling the // ScenePresence's handling routine. AgentUpdateArgs aua = new AgentUpdateArgs(); aua.AgentID = sp.UUID; aua.BodyRotation = sp.Rotation; aua.CameraAtAxis = sp.CameraAtAxis; aua.CameraCenter = sp.CameraPosition; aua.CameraLeftAxis = sp.CameraLeftAxis; aua.CameraUpAxis = sp.CameraUpAxis; aua.ClientAgentPosition = sp.AbsolutePosition; aua.ControlFlags = sp.AgentControlFlags; aua.Far = sp.DrawDistance; aua.Flags = 0; aua.HeadRotation = sp.Rotation; // this is wrong but the only thing we can do aua.State = sp.State; aua.UseClientAgentPosition = true; sp.HandleAgentUpdate(null, aua); }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> 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); if (IsChildAgent) { // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); return; } ++m_movementUpdateCount; if (m_movementUpdateCount < 1) m_movementUpdateCount = 1; #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; if (!m_pos.IsFinite()) { m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_pos; } #endregion Sanity Checking #region Inputs 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_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; #endregion Inputs // // Make anims work for client side autopilot // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0) // m_updateCount = UPDATE_COUNT; // // // Make turning in place work // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0 || // (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) // m_updateCount = UPDATE_COUNT; if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { 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); if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) HandleAgentSitOnGround(); // In the future, these values might need to go global. // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; State = agentData.State; PhysicsActor actor = PhysicsActor; if (actor == null) { SendControlsToScripts(flagsForScripts); return; } if (AllowMovement && !SitGround) { Quaternion bodyRotation = agentData.BodyRotation; bool update_rotation = false; if (bodyRotation != Rotation) { Rotation = bodyRotation; update_rotation = true; } bool update_movementflag = false; if (agentData.UseClientAgentPosition) { MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; MoveToPositionTarget = agentData.ClientAgentPosition; } int i = 0; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; bool newFlying = actor.Flying; if (ForceFly) newFlying = true; else if (FlyDisabled) newFlying = false; else newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != newFlying) { // Note: ScenePresence.Flying is actually fetched from the physical actor // so setting PhysActor.Flying here also sets the ScenePresence's value. actor.Flying = newFlying; update_movementflag = true; } if (ParentID == 0) { bool bAllowUpdateMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if (!Flying && (m_mouseLook || m_leftButtonDown)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; // The fact that MovementFlag is a byte needs to be fixed // it really should be a uint // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. uint nudgehack = 250; foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { if (((uint)flags & (uint)DCF) != 0) { DCFlagKeyPressed = true; try { agent_control_v3 += dirVectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) { // Why did I get this? } if ((MovementFlag & (byte)(uint)DCF) == 0) { if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) { MovementFlag |= (byte)nudgehack; } //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); MovementFlag += (byte)(uint)DCF; update_movementflag = true; } } else { if ((MovementFlag & (byte)(uint)DCF) != 0 || ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) && ((MovementFlag & (byte)nudgehack) == nudgehack)) ) // This or is for Nudge forward { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); MovementFlag -= ((byte)(uint)DCF); update_movementflag = true; /* if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((MovementFlag & (byte)nudgehack) == nudgehack)) { m_log.Debug("Removed Hack flag"); } */ } else { bAllowUpdateMoveToPosition = true; } } i++; } if (MovingToTarget) { // If the user has pressed a key then we want to cancel any move to target. if (DCFlagKeyPressed) { ResetMoveToTarget(); update_movementflag = true; } else if (bAllowUpdateMoveToPosition) { // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a // certain position. It's only check for tolerance on returning to that position is 0.2 // rather than 1, at which point it removes its force target. if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2 : 1, ref agent_control_v3)) update_movementflag = true; } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (Flying && !ForceFly) { // Landing detection code // Are the landing controls requirements filled? bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); if (Flying && IsColliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't // want to do it every step when flying. if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) StopFlying(); } } // If the agent update does move the avatar, then calculate the force ready for the velocity update, // which occurs later in the main scene loop if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { // m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, ur = {4}", // m_scene.RegionInfo.RegionName, agent_control_v3, Name, update_movementflag, update_rotation); AddNewMovement(agent_control_v3); } // else // { // if (!update_movementflag) // { // m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false", // m_scene.RegionInfo.RegionName, agent_control_v3, Name); // } // } if (update_movementflag && ParentID == 0) Animator.UpdateMovementAnimations(); SendControlsToScripts(flagsForScripts); } m_scene.EventManager.TriggerOnClientMovement(this); TriggerScenePresenceUpdated(); }
protected virtual void OnBotAgentUpdate(uint controlFlag, Quaternion bodyRotation) { if (OnAgentUpdate != null) { AgentUpdateArgs pack = new AgentUpdateArgs(); pack.ControlFlags = controlFlag; pack.BodyRotation = bodyRotation; OnAgentUpdate(this, pack); } }
private void Update() { frame++; if (frame > 20) { frame = 0; if (OnAgentUpdate != null) { AgentUpdateArgs pack = new AgentUpdateArgs(); pack.ControlFlags = movementFlag; pack.BodyRotation = bodyDirection; OnAgentUpdate(this, pack); } if (flyState == 0) { movementFlag = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY | (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG; flyState = 1; } else if (flyState == 1) { movementFlag = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY | (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; flyState = 2; } else { movementFlag = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; flyState = 0; } if (count >= 10) { if (OnChatFromClient != null) { OSChatMessage args = new OSChatMessage(); args.Message = "Hey You! Get out of my Home. This is my Region"; args.Channel = 0; args.From = FirstName + " " + LastName; args.Scene = m_scene; args.Position = new Vector3(128, 128, 26); args.Sender = this; args.Type = ChatTypeEnum.Shout; OnChatFromClient(this, args); } count = -1; } count++; } }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> public virtual void HandleAgentUpdate (IClientAPI remoteClient, AgentUpdateArgs agentData) { m_perfMonMS = Util.EnvironmentTickCount(); ++m_movementUpdateCount; if (m_movementUpdateCount < 1) m_movementUpdateCount = 1; #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { OutOfBoundsCall(Vector3.Zero); return; } #endregion Sanity Checking #region Inputs if (Frozen) return; //Do nothing, just end AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; Quaternion bodyRotation = agentData.BodyRotation; //Check to see whether ray casting needs done // We multiply by 10 so that we don't trigger it when the camera moves slightly (as its 2 meter change) if (Util.GetFlatDistanceTo(agentData.CameraCenter, m_lastCameraCenter) > SIGNIFICANT_MOVEMENT * 10) { m_lastCameraCenter = agentData.CameraCenter; Scene.AuroraEventManager.FireGenericEventHandler("SignficantCameraMovement", this); } // Camera location in world. We'll need to raytrace // from this location from time to time. m_CameraCenter = agentData.CameraCenter; // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion m_CameraAtAxis = agentData.CameraAtAxis; m_CameraLeftAxis = agentData.CameraLeftAxis; m_CameraUpAxis = agentData.CameraUpAxis; // The Agent's Draw distance setting DrawDistance = agentData.Far; // Check if Client has camera in 'follow cam' or 'build' mode. Vector3 camdif = (Vector3.One * m_bodyRot - Vector3.One * CameraRotation); m_followCamAuto = ((m_CameraUpAxis.Z > 0.959f && m_CameraUpAxis.Z < 0.98f) && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)); m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; m_isAway = (flags & AgentManager.ControlFlags.AGENT_CONTROL_AWAY) != 0; #endregion Inputs if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); } //MainConsole.Instance.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(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); } } if (!m_CameraCenter.IsFinite()) { m_CameraCenter = new Vector3(128, 128, 128); } IScriptControllerModule m = RequestModuleInterface<IScriptControllerModule> (); if (m != null) //Tell any scripts about it m.OnNewMovement (ref flags); if (m_autopilotMoving) CheckAtSitTarget(); // In the future, these values might need to go global. // Here's where you get them. if (!SitGround) SitGround = (flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0; m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; m_state = agentData.State; PhysicsCharacter actor = PhysicsActor; if (actor == null) { //This happens while sitting, don't spam it //MainConsole.Instance.Debug("Null physical actor in AgentUpdate in " + m_scene.RegionInfo.RegionName); return; } bool update_movementflag = false; if (AllowMovement && !SitGround && !Frozen) { if (FallenStandUp) { //Poke the animator a bit Animator.UpdateMovementAnimations(false); m_bodyRot = bodyRotation; AddNewMovement (Vector3.Zero, bodyRotation); return; } if (agentData.UseClientAgentPosition) { m_moveToPositionInProgress = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; m_moveToPositionTarget = agentData.ClientAgentPosition; } int i = 0; bool update_rotation = false; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; Quaternion q = bodyRotation; bool oldflying = PhysicsActor.Flying; if (m_forceFly) actor.Flying = true; else if (m_flyDisabled) actor.Flying = false; else actor.Flying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != oldflying) update_movementflag = true; if (q != m_bodyRot) { m_bodyRot = q; update_rotation = true; } if (m_parentID == UUID.Zero) { bool bAllowUpdateMoveToPosition = false; bool bResetMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if ((m_mouseLook && !m_physicsActor.Flying) || (m_leftButtonDown && !m_physicsActor.Flying)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; // The fact that m_movementflag is a byte needs to be fixed // it really should be a uint const uint nudgehack = 250; //Do these two like this to block out all others because it will slow it down if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) { bResetMoveToPosition = true; DCFlagKeyPressed = true; agent_control_v3 += dirVectors[8]; } else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) { bResetMoveToPosition = true; DCFlagKeyPressed = true; agent_control_v3 += dirVectors[9]; } else { foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { if (((uint)flags & (uint)DCF) != 0) { bResetMoveToPosition = true; DCFlagKeyPressed = true; agent_control_v3 += dirVectors[i]; //MainConsole.Instance.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); if ((m_movementflag & (uint)DCF) == 0) { if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) { // m_movementflag |= (byte)nudgehack; m_movementflag |= nudgehack; } m_movementflag += (uint)DCF; update_movementflag = true; } } else { if ((m_movementflag & (uint)DCF) != 0 || ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((m_movementflag & nudgehack) == nudgehack)) ) // This or is for Nudge forward { m_movementflag -= ((uint)DCF); update_movementflag = true; /* if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((m_movementflag & (byte)nudgehack) == nudgehack)) { MainConsole.Instance.Debug("Removed Hack flag"); } */ } else { bAllowUpdateMoveToPosition = true; } } i++; } } //Paupaw:Do Proper PID for Autopilot here if (bResetMoveToPosition) { m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; bAllowUpdateMoveToPosition = false; } if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving)) { //Check the error term of the current position in relation to the target position if (Util.GetFlatDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 0.5f) { // we are close enough to the target m_moveToPositionTarget = Vector3.Zero; m_moveToPositionInProgress = false; update_movementflag = true; } else { try { // move avatar in 2D at one meter/second towards target, in avatar coordinate frame. // This movement vector gets added to the velocity through AddNewMovement(). // Theoretically we might need a more complex PID approach here if other // unknown forces are acting on the avatar and we need to adaptively respond // to such forces, but the following simple approach seems to works fine. Vector3 LocalVectorToTarget3D= (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords // * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords * Quaternion.Inverse(bodyRotation); // mult by matix is faster but with creation, use *quarternion // Ignore z component of vector Vector3 LocalVectorToTarget2D; LocalVectorToTarget2D.X = LocalVectorToTarget3D.X; LocalVectorToTarget2D.Y = LocalVectorToTarget3D.Y; LocalVectorToTarget2D.Z = 0f; agent_control_v3 += LocalVectorToTarget2D; // update avatar movement flags. the avatar coordinate system is as follows: // // +X (forward) // // ^ // | // | // | // | // (left) +Y <--------o--------> -Y // avatar // | // | // | // | // v // -X // // based on the above avatar coordinate system, classify the movement into // one of left/right/back/forward. if (LocalVectorToTarget2D.Y > 0)//MoveLeft { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; //AgentControlFlags AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; update_movementflag = true; } else if (LocalVectorToTarget2D.Y < 0) //MoveRight { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; update_movementflag = true; } if (LocalVectorToTarget2D.X < 0) //MoveBack { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; update_movementflag = true; } else if (LocalVectorToTarget2D.X > 0) //Move Forward { m_movementflag += (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; update_movementflag = true; } } catch (Exception e) { //Avoid system crash, can be slower but... MainConsole.Instance.DebugFormat("Crash! {0}", e); } } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (m_physicsActor != null && m_physicsActor.Flying && !m_forceFly) { // Landing detection code // Are the landing controls requirements filled? bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); // Are the collision requirements fulfilled? bool colliding = (m_physicsActor.IsColliding == true); if (m_physicsActor.Flying && colliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't // want to do it every step when flying. // then call it in the if... //The == Zero and Z > 0.1 are to stop people from flying and then falling down because the physics engine hasn't calculted the push yet if (Velocity != Vector3.Zero && Math.Abs(Velocity.Z) > 0.05 && (Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) { StopFlying (); SendTerseUpdateToAllClients (); } } } // If the agent update does move the avatar, then calculate the force ready for the velocity update, // which occurs later in the main scene loop if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { // MainConsole.Instance.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); // MainConsole.Instance.DebugFormat( // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); AddNewMovement(agent_control_v3, q); } } if (update_movementflag && (m_parentID == UUID.Zero) && !SitGround && flags == AgentManager.ControlFlags.NONE) Animator.UpdateMovementAnimations(true); IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_scene.RequestModuleInterface<IMonitorModule>().GetMonitor(m_scene.RegionInfo.RegionID.ToString(), MonitorModuleHelper.AgentUpdateCount); if (reporter != null) reporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); }
/// <summary> /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering. /// </summary> private 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; // 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(); }
/// <summary> /// This is the event handler for client movement. If a client is moving, this event is triggering. /// </summary> public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //if (m_isChildAgent) //{ // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); // return; //} m_perfMonMS = Util.EnvironmentTickCount(); ++m_movementUpdateCount; if (m_movementUpdateCount < 1) m_movementUpdateCount = 1; #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; if (!m_pos.IsFinite()) { m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } AddToPhysicalScene(false); } else { m_LastFinitePos = m_pos; } #endregion Sanity Checking #region Inputs AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; Quaternion bodyRotation = agentData.BodyRotation; // Camera location in world. We'll need to raytrace // from this location from time to time. m_CameraCenter = agentData.CameraCenter; if (Vector3.Distance(m_lastCameraCenter, m_CameraCenter) >= Scene.RootReprioritizationDistance) { ReprioritizeUpdates(); m_lastCameraCenter = m_CameraCenter; } // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion m_CameraAtAxis = agentData.CameraAtAxis; m_CameraLeftAxis = agentData.CameraLeftAxis; m_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. // m_DrawDistance = agentData.Far; m_DrawDistance = Scene.DefaultDrawDistance; // Check if Client has camera in 'follow cam' or 'build' mode. Vector3 camdif = (Vector3.One * m_bodyRot - Vector3.One * CameraRotation); m_followCamAuto = ((m_CameraUpAxis.Z > 0.959f && m_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; #endregion Inputs if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { 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(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); } } lock (scriptedcontrols) { if (scriptedcontrols.Count > 0) { SendControlToScripts((uint)flags); flags = RemoveIgnoredControls(flags, IgnoredControls); } } if (m_autopilotMoving) CheckAtSitTarget(); if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) { // TODO: This doesn't prevent the user from walking yet. // Setting parent ID would fix this, if we knew what value // to use. Or we could add a m_isSitting variable. //Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); SitGround = true; } // In the future, these values might need to go global. // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; m_state = agentData.State; PhysicsActor actor = PhysicsActor; if (actor == null) { return; } if (m_allowMovement && !SitGround) { bool update_movementflag = false; if (agentData.UseClientAgentPosition) { MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; MoveToPositionTarget = agentData.ClientAgentPosition; } int i = 0; bool update_rotation = false; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; Quaternion q = bodyRotation; bool oldflying = PhysicsActor.Flying; if (m_forceFly) actor.Flying = true; else if (m_flyDisabled) actor.Flying = false; else actor.Flying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); if (actor.Flying != oldflying) update_movementflag = true; if (q != m_bodyRot) { m_bodyRot = q; update_rotation = true; } if (m_parentID == 0) { bool bAllowUpdateMoveToPosition = false; Vector3[] dirVectors; // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. if ((m_mouseLook && !m_physicsActor.Flying) || (m_leftButtonDown && !m_physicsActor.Flying)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; // The fact that m_movementflag is a byte needs to be fixed // it really should be a uint // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. uint nudgehack = 250; foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { if (((uint)flags & (uint)DCF) != 0) { DCFlagKeyPressed = true; try { agent_control_v3 += dirVectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) { // Why did I get this? } if ((m_movementflag & (byte)(uint)DCF) == 0) { if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) { m_movementflag |= (byte)nudgehack; } m_movementflag += (byte)(uint)DCF; update_movementflag = true; } } else { if ((m_movementflag & (byte)(uint)DCF) != 0 || ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((m_movementflag & (byte)nudgehack) == nudgehack)) ) // This or is for Nudge forward { m_movementflag -= ((byte)(uint)DCF); update_movementflag = true; /* if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) && ((m_movementflag & (byte)nudgehack) == nudgehack)) { m_log.Debug("Removed Hack flag"); } */ } else { bAllowUpdateMoveToPosition = true; } } i++; } if (MovingToTarget) { // If the user has pressed a key then we want to cancel any move to target. if (DCFlagKeyPressed) { ResetMoveToTarget(); update_movementflag = true; } else if (bAllowUpdateMoveToPosition) { if (HandleMoveToTargetUpdate(ref agent_control_v3, bodyRotation)) update_movementflag = true; } } } // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. // Only do this if we're flying if (m_physicsActor != null && m_physicsActor.Flying && !m_forceFly) { // Landing detection code // Are the landing controls requirements filled? bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); // Are the collision requirements fulfilled? bool colliding = (m_physicsActor.IsColliding == true); if (m_physicsActor.Flying && colliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't // want to do it every step when flying. if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) StopFlying(); } } // If the agent update does move the avatar, then calculate the force ready for the velocity update, // which occurs later in the main scene loop if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { // m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); // m_log.DebugFormat( // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); AddNewMovement(agent_control_v3, q); } if (update_movementflag && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) == 0) && (m_parentID == 0) && !SitGround) Animator.UpdateMovementAnimations(); } m_scene.EventManager.TriggerOnClientMovement(this); m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); }