public void addCollider(uint localID, ContactPoint contact) { Cleared = false; /*ContactPoint oldCol; if(!m_objCollisionList.TryGetValue(localID, out oldCol)) { */ lock (m_objCollisionList) m_objCollisionList[localID] = contact; /*} else { if(oldCol.PenetrationDepth < contact.PenetrationDepth) lock(m_objCollisionList) m_objCollisionList[localID] = contact; }*/ }
public void PhysicsCollision(EventArgs e) { // single threaded here if (e == null) return; CollisionEventUpdate a = (CollisionEventUpdate) e; Dictionary<uint, ContactPoint> collissionswith = a.m_objCollisionList; List<uint> thisHitColliders = new List<uint>(); List<uint> startedColliders = new List<uint>(); ContactPoint startedCollider = new ContactPoint(); // calculate things that started colliding this time // and build up list of colliders this time foreach (uint localID in collissionswith.Keys) { thisHitColliders.Add(localID); if (!m_lastColliders.Contains(localID)) { startedCollider = collissionswith[localID]; startedColliders.Add(localID); } //MainConsole.Instance.Debug("[OBJECT]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString()); } // calculate things that ended colliding #if (!ISWIN) List<uint> endedColliders = new List<uint>(); foreach (uint localId in m_lastColliders) { if (!thisHitColliders.Contains(localId)) endedColliders.Add(localId); } #else List<uint> endedColliders = m_lastColliders.Where(localID => !thisHitColliders.Contains(localID)).ToList(); #endif //add the items that started colliding this time to the last colliders list. m_lastColliders.AddRange(startedColliders); // remove things that ended colliding from the last colliders list foreach (uint localID in endedColliders) m_lastColliders.Remove(localID); if (m_parentGroup == null) return; if (m_parentGroup.IsDeleted) return; const string SoundGlassCollision = "6a45ba0b-5775-4ea8-8513-26008a17f873"; const string SoundMetalCollision = "9e5c1297-6eed-40c0-825a-d9bcd86e3193"; const string SoundStoneCollision = "9538f37c-456e-4047-81be-6435045608d4"; const string SoundFleshCollision = "dce5fdd4-afe4-4ea1-822f-dd52cac46b08"; const string SoundPlasticCollision = "0e24a717-b97e-4b77-9c94-b59a5a88b2da"; const string SoundRubberCollision = "153c8bf7-fb89-4d89-b263-47e58b1b4774"; const string SoundWoodCollision = "063c97d3-033a-4e9b-98d8-05c8074922cb"; // play the sound. if (startedColliders.Count > 0 && CollisionSound != UUID.Zero && CollisionSoundVolume > 0.0f) { SendSound(CollisionSound.ToString(), CollisionSoundVolume, true, 0, 0, false, false); } else if (startedColliders.Count > 0) { switch (startedCollider.Type) { case ActorTypes.Agent: break; // Agents will play the sound so we don't case ActorTypes.Ground: SendSound(SoundWoodCollision, 1, true, 0, 0, false, false); break; //Always play the click or thump sound when hitting ground case ActorTypes.Prim: if (m_material == OpenMetaverse.Material.Flesh) SendSound(SoundFleshCollision, 1, true, 0, 0, false, false); else if (m_material == OpenMetaverse.Material.Glass) SendSound(SoundGlassCollision, 1, true, 0, 0, false, false); else if (m_material == OpenMetaverse.Material.Metal) SendSound(SoundMetalCollision, 1, true, 0, 0, false, false); else if (m_material == OpenMetaverse.Material.Plastic) SendSound(SoundPlasticCollision, 1, true, 0, 0, false, false); else if (m_material == OpenMetaverse.Material.Rubber) SendSound(SoundRubberCollision, 1, true, 0, 0, false, false); else if (m_material == OpenMetaverse.Material.Stone) SendSound(SoundStoneCollision, 1, true, 0, 0, false, false); else if (m_material == OpenMetaverse.Material.Wood) SendSound(SoundWoodCollision, 1, true, 0, 0, false, false); break; //Play based on material type in prim2prim collisions default: break; //Unclear of what this object is, no sounds } } if (CollisionSprite != UUID.Zero && CollisionSoundVolume > 0.0f) // The collision volume isn't a mistake, its an SL feature/bug { // TODO: make a sprite! } if (((AggregateScriptEvents & scriptEvents.collision) != 0) || ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || ((AggregateScriptEvents & scriptEvents.land_collision) != 0) || ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || (CollisionSound != UUID.Zero) || PassCollisions != 2) { if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision_start) != 0 || (m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision) != 0) { // do event notification if (startedColliders.Count > 0) { ColliderArgs StartCollidingMessage = new ColliderArgs(); List<DetectedObject> colliding = new List<DetectedObject>(); foreach (uint localId in startedColliders) { if (localId != 0) { // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; ISceneChildEntity obj = m_parentGroup.Scene.GetSceneObjectPart(localId); string data = ""; if (obj != null) { if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this object if (found) { DetectedObject detobj = new DetectedObject { keyUUID = obj.UUID, nameStr = obj.Name, ownerUUID = obj.OwnerID, posVector = obj.AbsolutePosition, rotQuat = obj.GetWorldRotation(), velVector = obj.Velocity, colliderType = 0, groupUUID = obj.GroupID }; colliding.Add(detobj); } //If it is 0, it is to not accept collisions from this object else { } } else { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this object, so this other object will not work if (!found) { DetectedObject detobj = new DetectedObject { keyUUID = obj.UUID, nameStr = obj.Name, ownerUUID = obj.OwnerID, posVector = obj.AbsolutePosition, rotQuat = obj.GetWorldRotation(), velVector = obj.Velocity, colliderType = 0, groupUUID = obj.GroupID }; colliding.Add(detobj); } } } else { IScenePresence av = ParentGroup.Scene.GetScenePresence(localId); if (av != null) { if (av.LocalId == localId) { if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this avatar if (found) { DetectedObject detobj = new DetectedObject { keyUUID = av.UUID, nameStr = av.ControllingClient.Name, ownerUUID = av.UUID, posVector = av.AbsolutePosition, rotQuat = av.Rotation, velVector = av.Velocity, colliderType = 0, groupUUID = av.ControllingClient.ActiveGroupId }; colliding.Add(detobj); } //If it is 0, it is to not accept collisions from this avatar else { } } else { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work if (!found) { DetectedObject detobj = new DetectedObject { keyUUID = av.UUID, nameStr = av.ControllingClient.Name, ownerUUID = av.UUID, posVector = av.AbsolutePosition, rotQuat = av.Rotation, velVector = av.Velocity, colliderType = 0, groupUUID = av.ControllingClient.ActiveGroupId }; colliding.Add(detobj); } } } } } } } if (colliding.Count > 0) { StartCollidingMessage.Colliders = colliding; // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; //Always send to the prim it is occuring to m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart(this, StartCollidingMessage); if ((this.UUID != this.ParentGroup.RootPart.UUID)) { const int PASS_IF_NOT_HANDLED = 0; const int PASS_ALWAYS = 1; const int PASS_NEVER = 2; if (this.PassCollisions == PASS_NEVER) { } if (this.PassCollisions == PASS_ALWAYS) { m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart( this.ParentGroup.RootPart, StartCollidingMessage); } else if (((this.ScriptEvents & scriptEvents.collision_start) == 0) && this.PassCollisions == PASS_IF_NOT_HANDLED) //If no event in this prim, pass to parent { m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart( this.ParentGroup.RootPart, StartCollidingMessage); } } } } } if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision) != 0) { if (m_lastColliders.Count > 0) { ColliderArgs CollidingMessage = new ColliderArgs(); List<DetectedObject> colliding = new List<DetectedObject>(); foreach (uint localId in m_lastColliders) { if (localId != 0) { if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; ISceneChildEntity obj = m_parentGroup.Scene.GetSceneObjectPart(localId); string data = ""; if (obj != null) { if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this object if (found) { DetectedObject detobj = new DetectedObject { keyUUID = obj.UUID, nameStr = obj.Name, ownerUUID = obj.OwnerID, posVector = obj.AbsolutePosition, rotQuat = obj.GetWorldRotation(), velVector = obj.Velocity, colliderType = 0, groupUUID = obj.GroupID }; colliding.Add(detobj); } //If it is 0, it is to not accept collisions from this object else { } } else { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this object, so this other object will not work if (!found) { DetectedObject detobj = new DetectedObject { keyUUID = obj.UUID, nameStr = obj.Name, ownerUUID = obj.OwnerID, posVector = obj.AbsolutePosition, rotQuat = obj.GetWorldRotation(), velVector = obj.Velocity, colliderType = 0, groupUUID = obj.GroupID }; colliding.Add(detobj); } } } else { IScenePresence av = ParentGroup.Scene.GetScenePresence(localId); if (av != null) { if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this avatar if (found) { DetectedObject detobj = new DetectedObject { keyUUID = av.UUID, nameStr = av.ControllingClient.Name, ownerUUID = av.UUID, posVector = av.AbsolutePosition, rotQuat = av.Rotation, velVector = av.Velocity, colliderType = 0, groupUUID = av.ControllingClient.ActiveGroupId }; colliding.Add(detobj); } //If it is 0, it is to not accept collisions from this avatar else { } } else { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work if (!found) { DetectedObject detobj = new DetectedObject { keyUUID = av.UUID, nameStr = av.ControllingClient.Name, ownerUUID = av.UUID, posVector = av.AbsolutePosition, rotQuat = av.Rotation, velVector = av.Velocity, colliderType = 0, groupUUID = av.ControllingClient.ActiveGroupId }; colliding.Add(detobj); } } } } } } if (colliding.Count > 0) { CollidingMessage.Colliders = colliding; // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; m_parentGroup.Scene.EventManager.TriggerScriptColliding(this, CollidingMessage); if ((this.UUID != this.ParentGroup.RootPart.UUID)) { const int PASS_IF_NOT_HANDLED = 0; const int PASS_ALWAYS = 1; const int PASS_NEVER = 2; if (this.PassCollisions == PASS_NEVER) { } if (this.PassCollisions == PASS_ALWAYS) { m_parentGroup.Scene.EventManager.TriggerScriptColliding(this.ParentGroup.RootPart, CollidingMessage); } else if (((this.ScriptEvents & scriptEvents.collision) == 0) && this.PassCollisions == PASS_IF_NOT_HANDLED) //If no event in this prim, pass to parent { m_parentGroup.Scene.EventManager.TriggerScriptColliding( this.ParentGroup.RootPart, CollidingMessage); } } } } } if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision_end) != 0) { if (endedColliders.Count > 0) { ColliderArgs EndCollidingMessage = new ColliderArgs(); List<DetectedObject> colliding = new List<DetectedObject>(); foreach (uint localId in endedColliders) { if (localId != 0) { // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; ISceneChildEntity obj = m_parentGroup.Scene.GetSceneObjectPart(localId); string data = ""; if (obj != null) { if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(obj.Name)) { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this object if (found) { DetectedObject detobj = new DetectedObject { keyUUID = obj.UUID, nameStr = obj.Name, ownerUUID = obj.OwnerID, posVector = obj.AbsolutePosition, rotQuat = obj.GetWorldRotation(), velVector = obj.Velocity, colliderType = 0, groupUUID = obj.GroupID }; colliding.Add(detobj); } //If it is 0, it is to not accept collisions from this object else { } } else { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this object, so this other object will not work if (!found) { DetectedObject detobj = new DetectedObject { keyUUID = obj.UUID, nameStr = obj.Name, ownerUUID = obj.OwnerID, posVector = obj.AbsolutePosition, rotQuat = obj.GetWorldRotation(), velVector = obj.Velocity, colliderType = 0, groupUUID = obj.GroupID }; colliding.Add(detobj); } } } else { IScenePresence av = ParentGroup.Scene.GetScenePresence(localId); if (av != null) { if (av.LocalId == localId) { if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this avatar if (found) { DetectedObject detobj = new DetectedObject { keyUUID = av.UUID, nameStr = av.ControllingClient.Name, ownerUUID = av.UUID, posVector = av.AbsolutePosition, rotQuat = av.Rotation, velVector = av.Velocity, colliderType = 0, groupUUID = av.ControllingClient.ActiveGroupId }; colliding.Add(detobj); } //If it is 0, it is to not accept collisions from this avatar else { } } else { bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data); //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work if (!found) { DetectedObject detobj = new DetectedObject { keyUUID = av.UUID, nameStr = av.ControllingClient.Name, ownerUUID = av.UUID, posVector = av.AbsolutePosition, rotQuat = av.Rotation, velVector = av.Velocity, colliderType = 0, groupUUID = av.ControllingClient.ActiveGroupId }; colliding.Add(detobj); } } } } } } } if (colliding.Count > 0) { EndCollidingMessage.Colliders = colliding; // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; m_parentGroup.Scene.EventManager.TriggerScriptCollidingEnd(this, EndCollidingMessage); if ((this.UUID != this.ParentGroup.RootPart.UUID)) { const int PASS_IF_NOT_HANDLED = 0; const int PASS_ALWAYS = 1; const int PASS_NEVER = 2; if (this.PassCollisions == PASS_NEVER) { } if (this.PassCollisions == PASS_ALWAYS) { m_parentGroup.Scene.EventManager.TriggerScriptCollidingEnd( this.ParentGroup.RootPart, EndCollidingMessage); } else if (((this.ScriptEvents & scriptEvents.collision_end) == 0) && this.PassCollisions == PASS_IF_NOT_HANDLED) //If no event in this prim, pass to parent { m_parentGroup.Scene.EventManager.TriggerScriptCollidingEnd( this.ParentGroup.RootPart, EndCollidingMessage); } } } } } if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision_start) != 0 || (m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision) != 0) { if (startedColliders.Count > 0) { ColliderArgs LandStartCollidingMessage = new ColliderArgs(); List<DetectedObject> colliding = (from localId in startedColliders where localId == 0 select new DetectedObject { keyUUID = UUID.Zero, nameStr = "", ownerUUID = UUID.Zero, posVector = m_parentGroup.RootPart.AbsolutePosition, rotQuat = Quaternion.Identity, velVector = Vector3.Zero, colliderType = 0, groupUUID = UUID.Zero }).ToList(); if (colliding.Count > 0) { LandStartCollidingMessage.Colliders = colliding; // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; m_parentGroup.Scene.EventManager.TriggerScriptLandCollidingStart(this, LandStartCollidingMessage); if ((this.UUID != this.ParentGroup.RootPart.UUID)) { const int PASS_IF_NOT_HANDLED = 0; const int PASS_ALWAYS = 1; const int PASS_NEVER = 2; if (this.PassCollisions == PASS_NEVER) { } if (this.PassCollisions == PASS_ALWAYS) { m_parentGroup.Scene.EventManager.TriggerScriptLandCollidingStart( this.ParentGroup.RootPart, LandStartCollidingMessage); } else if (((this.ScriptEvents & scriptEvents.land_collision_start) == 0) && this.PassCollisions == PASS_IF_NOT_HANDLED) //If no event in this prim, pass to parent { m_parentGroup.Scene.EventManager.TriggerScriptLandCollidingStart( this.ParentGroup.RootPart, LandStartCollidingMessage); } } } } } if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision) != 0) { if (m_lastColliders.Count > 0) { ColliderArgs LandCollidingMessage = new ColliderArgs(); List<DetectedObject> colliding = new List<DetectedObject>(); foreach (uint localId in m_lastColliders) { if (localId == 0) { //Hope that all is left is ground! DetectedObject detobj = new DetectedObject { keyUUID = UUID.Zero, nameStr = "", ownerUUID = UUID.Zero, posVector = m_parentGroup.RootPart.AbsolutePosition, rotQuat = Quaternion.Identity, velVector = Vector3.Zero, colliderType = 0, groupUUID = UUID.Zero }; colliding.Add(detobj); } } if (colliding.Count > 0) { LandCollidingMessage.Colliders = colliding; // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; m_parentGroup.Scene.EventManager.TriggerScriptLandColliding(this, LandCollidingMessage); if ((this.UUID != this.ParentGroup.RootPart.UUID)) { const int PASS_IF_NOT_HANDLED = 0; const int PASS_ALWAYS = 1; const int PASS_NEVER = 2; if (this.PassCollisions == PASS_NEVER) { } if (this.PassCollisions == PASS_ALWAYS) { m_parentGroup.Scene.EventManager.TriggerScriptLandColliding(this.ParentGroup.RootPart, LandCollidingMessage); } else if (((this.ScriptEvents & scriptEvents.land_collision) == 0) && this.PassCollisions == PASS_IF_NOT_HANDLED) //If no event in this prim, pass to parent { m_parentGroup.Scene.EventManager.TriggerScriptLandColliding( this.ParentGroup.RootPart, LandCollidingMessage); } } } } } if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.land_collision_end) != 0) { if (endedColliders.Count > 0) { ColliderArgs LandEndCollidingMessage = new ColliderArgs(); List<DetectedObject> colliding = (from localId in startedColliders where localId == 0 select new DetectedObject { keyUUID = UUID.Zero, nameStr = "", ownerUUID = UUID.Zero, posVector = m_parentGroup.RootPart.AbsolutePosition, rotQuat = Quaternion.Identity, velVector = Vector3.Zero, colliderType = 0, groupUUID = UUID.Zero }).ToList(); if (colliding.Count > 0) { LandEndCollidingMessage.Colliders = colliding; // always running this check because if the user deletes the object it would return a null reference. if (m_parentGroup == null) return; if (m_parentGroup.Scene == null) return; m_parentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd(this, LandEndCollidingMessage); if ((this.UUID != this.ParentGroup.RootPart.UUID)) { const int PASS_IF_NOT_HANDLED = 0; const int PASS_ALWAYS = 1; const int PASS_NEVER = 2; if (this.PassCollisions == PASS_NEVER) { } if (this.PassCollisions == PASS_ALWAYS) { m_parentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd( this.ParentGroup.RootPart, LandEndCollidingMessage); } else if (((this.ScriptEvents & scriptEvents.land_collision_end) == 0) && this.PassCollisions == PASS_IF_NOT_HANDLED) //If no event in this prim, pass to parent { m_parentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd( this.ParentGroup.RootPart, LandEndCollidingMessage); } } } } } } }
/// <summary> /// This is our near callback. A geometry is near a body /// </summary> /// <param name = "space">The space that contains the geoms. Remember, spaces are also geoms</param> /// <param name = "g1">a geometry or space</param> /// <param name = "g2">another geometry or space</param> private void near(IntPtr space, IntPtr g1, IntPtr g2) { // no lock here! It's invoked from within Simulate(), which is thread-locked if (g1 == IntPtr.Zero || g2 == IntPtr.Zero || g1 == g2) return; // Test if we're colliding a geom with a space. // If so we have to drill down into the space recursively if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) { // Separating static prim geometry spaces. // We'll be calling near recursivly if one // of them is a space to find all of the // contact points in the space try { d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); } catch (Exception e) { MainConsole.Instance.WarnFormat("[PHYSICS]: SpaceCollide2 failed: {0} ", e); return; } return; } IntPtr b1 = d.GeomGetBody(g1); IntPtr b2 = d.GeomGetBody(g2); int FindContactsTime = Util.EnvironmentTickCount(); // Figure out how many contact points we have int count = 0; try { // Colliding Geom To Geom // This portion of the function 'was' blatantly ripped off from BoxStack.cs if (g1 == g2) return; // Can't collide with yourself if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); } catch (Exception e) { MainConsole.Instance.WarnFormat("[PHYSICS]: ode Collide failed: {0} ", e); PhysicsActor badObj; if (actor_name_map.TryGetValue(g1, out badObj)) if (badObj is AuroraODEPrim) RemovePrim((AuroraODEPrim)badObj); else if (badObj is AuroraODECharacter) RemoveAvatar((AuroraODECharacter)badObj); if (actor_name_map.TryGetValue(g2, out badObj)) if (badObj is AuroraODEPrim) RemovePrim((AuroraODEPrim)badObj); else if (badObj is AuroraODECharacter) RemoveAvatar((AuroraODECharacter)badObj); return; } if (count == 0) return; PhysicsActor p1; PhysicsActor p2; if (!actor_name_map.TryGetValue(g1, out p1)) p1 = PANull; if (!actor_name_map.TryGetValue(g2, out p2)) p2 = PANull; /* if (p1 is AuroraODEPrim && (p1 as AuroraODEPrim)._zeroFlag) (p1 as AuroraODEPrim)._zeroFlag = false; if (p2 is AuroraODEPrim && (p2 as AuroraODEPrim)._zeroFlag) (p2 as AuroraODEPrim)._zeroFlag = false; */ m_StatFindContactsTime = Util.EnvironmentTickCountSubtract(FindContactsTime); if (p1.CollisionScore >= float.MaxValue - count) p1.CollisionScore = 0; p1.CollisionScore += count; if (p2.CollisionScore >= float.MaxValue - count) p2.CollisionScore = 0; p2.CollisionScore += count; int ContactLoopTime = Util.EnvironmentTickCount(); ContactPoint maxDepthContact = new ContactPoint(); d.ContactGeom curContact = new d.ContactGeom(); int NotSkipedCount = 0; #region Contact Loop IntPtr joint = IntPtr.Zero; for (int i = 0; i < count; i++) { if (!GetCurContactGeom(i, ref curContact)) break; if (curContact.depth > maxDepthContact.PenetrationDepth) { maxDepthContact.PenetrationDepth = curContact.depth; maxDepthContact.Position.X = curContact.pos.X; maxDepthContact.Position.Y = curContact.pos.Y; maxDepthContact.Position.Z = curContact.pos.Z; maxDepthContact.Type = (ActorTypes) p1.PhysicsActorType; maxDepthContact.SurfaceNormal.X = curContact.normal.X; maxDepthContact.SurfaceNormal.Y = curContact.normal.Y; maxDepthContact.SurfaceNormal.Z = curContact.normal.Z; } bool p2col = true; // We only need to test p2 for 'jump crouch purposes' if (p2 is AuroraODECharacter && p1.PhysicsActorType == (int) ActorTypes.Prim) { // Testing if the collision is at the feet of the avatar if ((p2.Position.Z - maxDepthContact.Position.Z) < (p2.Size.Z*0.6f)) p2col = false; } p2.IsColliding = p2col; // Logic for collision handling // Note, that if *all* contacts are skipped (VolumeDetect) // The prim still detects (and forwards) collision events but // appears to be phantom for the world Boolean skipThisContact = false; if (p1 is PhysicsObject && ((PhysicsObject) p1).VolumeDetect) skipThisContact = true; // No collision on volume detect prims if (p2 is PhysicsObject && ((PhysicsObject) p2).VolumeDetect) skipThisContact = true; // No collision on volume detect prims if (curContact.depth < 0f) skipThisContact = true; if (!skipThisContact && m_filterCollisions && checkDupe(curContact, p2.PhysicsActorType)) skipThisContact = true; if (!skipThisContact) { NotSkipedCount++; // If we're colliding against terrain if (p1.PhysicsActorType == (int) ActorTypes.Ground) { if (p2.PhysicsActorType == (int) ActorTypes.Prim) { if (m_filterCollisions) _perloopContact.Add(curContact); ((AuroraODEPrim)p2).GetContactParam(p2, ref newGlobalcontact); joint = CreateContacJoint(ref curContact); } //Can't collide against anything else, agents do their own ground checks } else if ((p1.PhysicsActorType == (int) ActorTypes.Agent) && (p2.PhysicsActorType == (int) ActorTypes.Agent)) { GetContactParam(0.0f, AvatarContactBounce, ref newGlobalcontact); if (m_filterCollisions) _perloopContact.Add(curContact); joint = CreateContacJoint(ref curContact); } else if (p1.PhysicsActorType == (int) ActorTypes.Prim) { if (p2.PhysicsActorType == (int) ActorTypes.Agent) { ((AuroraODEPrim)p1).GetContactParam(p2, ref newGlobalcontact); if (m_filterCollisions) _perloopContact.Add(curContact); joint = CreateContacJoint(ref curContact); } else if (p2.PhysicsActorType == (int) ActorTypes.Prim) { if (m_filterCollisions) _perloopContact.Add(curContact); //Add restitution and friction changes ((AuroraODEPrim)p1).GetContactParam(p2, ref newGlobalcontact); joint = CreateContacJoint(ref curContact); } } if (m_global_contactcount < m_currentmaxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! { d.JointAttach(joint, b1, b2); m_global_contactcount++; joint = IntPtr.Zero; } } } #endregion m_StatContactLoopTime = Util.EnvironmentTickCountSubtract(ContactLoopTime); int CollisionAccountingTime = Util.EnvironmentTickCount(); if (NotSkipedCount > 0) { if (count > geomContactPointsStartthrottle) { // If there are more then 3 contact points, it's likely // that we've got a pile of objects, so ... // We don't want to send out hundreds of terse updates over and over again // so lets throttle them and send them again after it's somewhat sorted out. p2.ThrottleUpdates = true; } } collision_accounting_events(p1, p2, maxDepthContact); m_StatCollisionAccountingTime = Util.EnvironmentTickCountSubtract(CollisionAccountingTime); }
private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) { if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) return; FireCollisionEvent(p1, p2, contact); if (p1.SubscribedEvents()) p1.AddCollisionEvent(p2.LocalID, contact); if (p2.SubscribedEvents()) p2.AddCollisionEvent(p1.LocalID, contact); }
public void FireCollisionEvent(PhysicsActor actor, PhysicsActor collidedActor, ContactPoint contact) { if (OnCollisionEvent != null) { OnCollisionEvent(actor, collidedActor, contact); } }
public override void AddCollisionEvent(uint CollidedWith, ContactPoint contact) { }
public abstract void AddCollisionEvent(uint localID, ContactPoint contact);
public override void AddCollisionEvent(uint CollidedWith, ContactPoint contact) { CollisionEventsThisFrame.addCollider(CollidedWith, contact); }
private void AddODECollision(d.ContactGeom curContact, PhysicsActor p1, PhysicsActor p2, IntPtr b1, IntPtr b2, ContactPoint maxDepthContact, ref int NotSkipedCount) { IntPtr joint = IntPtr.Zero; bool p2col = true; // We only need to test p2 for 'jump crouch purposes' if (p2 is AuroraODECharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) { // Testing if the collision is at the feet of the avatar if ((p2.Position.Z - maxDepthContact.Position.Z) < (p2.Size.Z * 0.6f)) p2col = false; } p2.IsTruelyColliding = true; p2.IsColliding = p2col; // Logic for collision handling // Note, that if *all* contacts are skipped (VolumeDetect) // The prim still detects (and forwards) collision events but // appears to be phantom for the world // No collision on volume detect prims if ((p1 is PhysicsObject && ((PhysicsObject)p1).VolumeDetect) || (p2 is PhysicsObject && ((PhysicsObject)p2).VolumeDetect)) return; if (curContact.depth < 0f) return;//Has to be penetrating if (m_filterCollisions && checkDupe(curContact, p2.PhysicsActorType)) return; if (m_filterCollisions) _perloopContact.Add(curContact); NotSkipedCount++; // If we're colliding against terrain if (p1.PhysicsActorType == (int)ActorTypes.Ground) { if (p2.PhysicsActorType == (int)ActorTypes.Prim) { ((AuroraODEPrim)p2).GetContactParam(p2, ref newGlobalcontact); joint = CreateContacJoint(curContact); } else { newGlobalcontact = new d.Contact(); newGlobalcontact.surface.mode |= d.ContactFlags.SoftERP; newGlobalcontact.surface.mu = 75; newGlobalcontact.surface.bounce = 0.1f; newGlobalcontact.surface.soft_erp = 0.05025f; //GetContactParam(0.0f, AvatarContactBounce, ref newGlobalcontact); joint = CreateContacJoint(curContact); } //Can't collide against anything else, agents do their own ground checks } else if ((p1.PhysicsActorType == (int)ActorTypes.Agent) && (p2.PhysicsActorType == (int)ActorTypes.Agent)) { GetContactParam(0.0f, AvatarContactBounce, ref newGlobalcontact); joint = CreateContacJoint(curContact); } else if (p1.PhysicsActorType == (int)ActorTypes.Prim) { //Add restitution and friction changes ((AuroraODEPrim)p1).GetContactParam(p2, ref newGlobalcontact); joint = CreateContacJoint(curContact); } if (m_global_contactcount < m_currentmaxContactsbeforedeath && joint != IntPtr.Zero) { d.JointAttach(joint, b1, b2); m_global_contactcount++; joint = IntPtr.Zero; } }
/// <summary> /// This is our near callback. A geometry is near a body /// </summary> /// <param name = "space">The space that contains the geoms. Remember, spaces are also geoms</param> /// <param name = "g1">a geometry or space</param> /// <param name = "g2">another geometry or space</param> private void near(IntPtr space, IntPtr g1, IntPtr g2) { if (g1 == IntPtr.Zero || g2 == IntPtr.Zero || g1 == g2) return; // Test if we're colliding a geom with a space. // If so we have to drill down into the space recursively if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) { // Separating static prim geometry spaces. // We'll be calling near recursivly if one // of them is a space to find all of the // contact points in the space try { d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); } catch (Exception e) { MainConsole.Instance.WarnFormat("[PHYSICS]: SpaceCollide2 failed: {0} ", e); return; } return; } IntPtr b1 = d.GeomGetBody(g1); IntPtr b2 = d.GeomGetBody(g2); // Figure out how many contact points we have int count = 0; try { // Colliding Geom To Geom // This portion of the function 'was' blatantly ripped off from BoxStack.cs if (g1 == g2) return; // Can't collide with yourself if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); } catch (Exception e) { MainConsole.Instance.WarnFormat("[PHYSICS]: ode Collide failed: {0} ", e.ToString()); PhysicsActor badObj; if (actor_name_map.TryGetValue(g1, out badObj)) if (badObj is AuroraODEPrim) RemovePrim((AuroraODEPrim)badObj); else if (badObj is AuroraODECharacter) RemoveAvatar((AuroraODECharacter)badObj); if (actor_name_map.TryGetValue(g2, out badObj)) if (badObj is AuroraODEPrim) RemovePrim((AuroraODEPrim)badObj); else if (badObj is AuroraODECharacter) RemoveAvatar((AuroraODECharacter)badObj); return; } if (count == 0) return; PhysicsActor p1; PhysicsActor p2; if (!actor_name_map.TryGetValue(g1, out p1)) p1 = PANull; if (!actor_name_map.TryGetValue(g2, out p2)) p2 = PANull; if (p1.CollisionScore >= float.MaxValue - count) p1.CollisionScore = 0; p1.CollisionScore += count; if (p2.CollisionScore >= float.MaxValue - count) p2.CollisionScore = 0; p2.CollisionScore += count; ContactPoint maxDepthContact = new ContactPoint(); d.ContactGeom curContact = new d.ContactGeom(); int NotSkipedCount = 0; //StatContactLoopTime = CollectTime(() => #region Contact Loop { for (int i = 0; i < count; i++) { if (!GetCurContactGeom(i, ref curContact)) break; if (curContact.depth > maxDepthContact.PenetrationDepth) { maxDepthContact.PenetrationDepth = curContact.depth; maxDepthContact.Position.X = curContact.pos.X; maxDepthContact.Position.Y = curContact.pos.Y; maxDepthContact.Position.Z = curContact.pos.Z; maxDepthContact.Type = (ActorTypes)p1.PhysicsActorType; maxDepthContact.SurfaceNormal.X = curContact.normal.X; maxDepthContact.SurfaceNormal.Y = curContact.normal.Y; maxDepthContact.SurfaceNormal.Z = curContact.normal.Z; } } } if (p1 is AuroraODECharacter || p2 is AuroraODECharacter) AddODECollision(curContact, p1, p2, b1, b2, maxDepthContact, ref NotSkipedCount); else { for (int i = 0; i < count; i++) { if (!GetCurContactGeom(i, ref curContact)) break; AddODECollision(curContact, p1, p2, b1, b2, maxDepthContact, ref NotSkipedCount); } } #endregion//); //StatCollisionAccountingTime = CollectTime(() => { if (NotSkipedCount > 0) { if (NotSkipedCount > geomContactPointsStartthrottle) { // If there are more then 3 contact points, it's likely // that we've got a pile of objects, so ... // We don't want to send out hundreds of terse updates over and over again // so lets throttle them and send them again after it's somewhat sorted out. p2.ThrottleUpdates = true; } } collision_accounting_events(p1, p2, maxDepthContact); }//); }
public override void AddCollisionEvent(uint localID, ContactPoint contact) { args.addCollider(localID, contact); }
public void FireCollisionEvent(PhysicsActor actor, PhysicsActor collidedActor, ContactPoint contact) { if (OnCollisionEvent != null) OnCollisionEvent(actor, collidedActor, contact); }
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name = "timeStep"></param> public void Move(float timeStep, ref List<AuroraODECharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) return; if (!m_shouldBePhysical) return; Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); d.Vector3 tempPos; d.BodyCopyPosition(Body, out tempPos); #region Flight Ceiling // rex, added height check if (m_pidControllerActive == false) { _zeroPosition = tempPos; } if (_parent_scene.m_useFlightCeilingHeight && tempPos.Z > _parent_scene.m_flightCeilingHeight) { tempPos.Z = _parent_scene.m_flightCeilingHeight; d.BodySetPosition(Body, tempPos.X, tempPos.Y, tempPos.Z); if (vel.Z > 0.0f) { vel.Z = 0.0f; d.BodySetLinearVel(Body, vel.X, vel.Y, vel.Z); } if (_target_velocity.Z > 0.0f) _target_velocity.Z = 0.0f; } // endrex #endregion #region NonFinite Pos Vector3 localPos = new Vector3(tempPos.X, tempPos.Y, tempPos.Z); if (!IsFinite(localPos)) { MainConsole.Instance.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); Shell = IntPtr.Zero; } return; } #endregion #region Check for out of region if (Position.X < 0.25f || Position.Y < 0.25f || Position.X > _parent_scene.Region.RegionSizeX - .25f || Position.Y > _parent_scene.Region.RegionSizeY - .25f) { if (!CheckForRegionCrossing()) { Vector3 newPos = Position; newPos.X = Util.Clip(Position.X, 0.75f, _parent_scene.Region.RegionSizeX - 0.75f); newPos.Y = Util.Clip(Position.Y, 0.75f, _parent_scene.Region.RegionSizeY - 0.75f); Position = newPos; d.BodySetPosition(Body, newPos.X, newPos.Y, newPos.Z); } } #endregion #region Movement Multiplier float movementmult = 1f; if (!m_alwaysRun) movementmult /= _parent_scene.avMovementDivisorWalk; else movementmult /= _parent_scene.avMovementDivisorRun; movementmult *= 10; movementmult *= SpeedModifier; // movementmult *= 1 / _parent_scene.TimeDilation; if (flying) movementmult *= _parent_scene.m_AvFlySpeed; #endregion #region Check for underground d.AABB aabb; d.GeomGetAABB(Shell, out aabb); float chrminZ = aabb.MinZ; Vector3 posch = localPos; float ftmp; if (flying) { ftmp = 0.75f*timeStep; posch.X += vel.X*ftmp; posch.Y += vel.Y*ftmp; } float groundHeight = _parent_scene.GetTerrainHeightAtXY(posch.X, posch.Y); if (chrminZ < groundHeight) { float depth = groundHeight - chrminZ; if (_target_velocity.Z < 0) _target_velocity.Z = 0; if (!flying) { if (vel.Z < -10f) vel.Z = -10f; vec.Z = -vel.Z*PID_D*1.5f + depth*PID_P*50.0f; } else { vec.Z = depth*PID_P*50.0f; } if (depth < 0.12f) { m_iscolliding = true; m_colliderfilter = 2; m_iscollidingGround = true; ContactPoint point = new ContactPoint { Type = ActorTypes.Ground, PenetrationDepth = depth, Position = {X = localPos.X, Y = localPos.Y, Z = chrminZ}, SurfaceNormal = new Vector3(0, 0, -1f) }; //0 is the ground localID AddCollisionEvent(0, point); vec.Z *= 0.5f; } else m_iscollidingGround = false; } else m_iscollidingGround = false; /* if(Flying && _target_velocity == Vector3.Zero && Math.Abs(vel.Z) < 0.1) notMoving = true; */ #endregion #region Movement #region Jump code if (IsJumping) { // if ((IsColliding) && m_preJumpCounter > _parent_scene.m_preJumpTime || m_preJumpCounter > 150) if ((IsColliding) && m_preJumpCounter > _parent_scene.m_preJumpTime || m_preJumpCounter > 150) { m_isJumping = false; m_preJumpCounter = 0; _target_velocity.Z = 0; } else m_preJumpCounter++; } else if (m_ispreJumping) { if (m_preJumpCounter == _parent_scene.m_preJumpTime) { m_ispreJumping = false; _target_velocity.X = m_preJumpForce.X*_parent_scene.m_preJumpForceMultiplierX; _target_velocity.Y = m_preJumpForce.Y*_parent_scene.m_preJumpForceMultiplierY; _target_velocity.Z = m_preJumpForce.Z*_parent_scene.m_preJumpForceMultiplierZ; m_preJumpCounter = 0; m_isJumping = true; } else { m_preJumpCounter++; TriggerMovementUpdate(); return; } } //This is for jumping on prims, since otherwise, you don't get off the ground sometimes // if (m_iscolliding && m_isJumping && _target_velocity.Z < 1 && !Flying) // _target_velocity.Z += m_preJumpForce.Z * _parent_scene.m_preJumpForceMultiplier; #endregion Vector3 gravForce = new Vector3(); // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity == Vector3.Zero && Math.Abs(vel.X) < 0.1 && Math.Abs(vel.Y) < 0.1 && Math.Abs(vel.Z) < 0.1 && (this.m_iscolliding || this.flying || (this._zeroFlag && _wasZeroFlagFlying == flying))) //This is so that if we get moved by something else, it will update us in the client { m_isJumping = false; // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _wasZeroFlagFlying = flying; _zeroPosition = tempPos; } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions // if target vel is zero why was it here ? vec.X = -vel.X*PID_D + (_zeroPosition.X - tempPos.X)*PID_P; vec.Y = -vel.Y*PID_D + (_zeroPosition.Y - tempPos.Y)*PID_P; // if (!realFlying) // vec.Z += - vel.Z * PID_D * 5; // else if (flying) vec.Z += -vel.Z*PID_D*0.5f + (_zeroPosition.Z - tempPos.Z)*PID_P; // _parent_scene.CalculateGravity(m_mass, tempPos, true, 0.15f, ref gravForce); // vec += gravForce; } } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding) { if (!flying) //If there is a ground collision, it sets flying to false, so check against real flying { // We're standing or walking on something if (_target_velocity.X != 0.0f) vec.X += (_target_velocity.X * movementmult - vel.X) * PID_D * 2; if (_target_velocity.Y != 0.0f) vec.Y += (_target_velocity.Y * movementmult - vel.Y) * PID_D * 2; if (_target_velocity.Z != 0.0f) vec.Z += (_target_velocity.Z * movementmult - vel.Z) * PID_D; /*// We're standing or walking on something vec.X += (_target_velocity.X*movementmult - vel.X)*PID_D*2; vec.Y += (_target_velocity.Y*movementmult - vel.Y)*PID_D*2; if (_target_velocity.Z > 0.0f) vec.Z += (_target_velocity.Z*movementmult - vel.Z)*PID_D; // + (_zeroPosition.Z - tempPos.Z) * PID_P)) _zeropos maybe bad here*/ } else { // We're flying and colliding with something vec.X += (_target_velocity.X*movementmult - vel.X)*PID_D*0.5f; vec.Y += (_target_velocity.Y*movementmult - vel.Y)*PID_D*0.5f; //if(_target_velocity.Z > 0) vec.Z += (_target_velocity.Z*movementmult - vel.Z)*PID_D*0.5f; } } else { if (flying) { // we're flying vec.X += (_target_velocity.X * movementmult - vel.X) * PID_D * 0.75f; vec.Y += (_target_velocity.Y * movementmult - vel.Y) * PID_D * 0.75f; } else { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. vec.X += (_target_velocity.X - vel.X) * PID_D * 0.85f; vec.Y += (_target_velocity.Y - vel.Y) * PID_D * 0.85f; } } if (flying) { #region Av gravity if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Should be stop avies from flying upwards { //Decay going up if (_target_velocity.Z > 0) { //How much should we force them down? float Multiplier = (_parent_scene.AllowAvsToEscapeGravity ? .03f : .1f); //How much should we force them down? float fudgeHeight = (_parent_scene.AllowAvsToEscapeGravity ? 80 : 30); //We add the 30 so that gravity is resonably strong once they pass the min height Multiplier *= tempPos.Z + fudgeHeight - _parent_scene.AvGravityHeight; //Limit these so that things don't go wrong if (Multiplier < 1) Multiplier = 1; float maxpower = (_parent_scene.AllowAvsToEscapeGravity ? 1.5f : 3f); if (Multiplier > maxpower) Multiplier = maxpower; _target_velocity.Z /= Multiplier; vel.Z /= Multiplier; } } #endregion vec.Z = (_target_velocity.Z*movementmult - vel.Z)*PID_D*0.5f; if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Add extra gravity vec.Z += ((10*_parent_scene.gravityz)*Mass); } } if (realFlying) { #region Auto Fly Height //Added for auto fly height. Kitto Flora //Changed to only check if the avatar is flying around, // Revolution: If the avatar is going down, they are trying to land (probably), so don't push them up to make it harder // Only if they are moving around sideways do we need to push them up if (_target_velocity.X != 0 || _target_velocity.Y != 0) { Vector3 forwardVel = new Vector3(_target_velocity.X > 0 ? 2 : (_target_velocity.X < 0 ? -2 : 0), _target_velocity.Y > 0 ? 2 : (_target_velocity.Y < 0 ? -2 : 0), 0); float target_altitude = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y) + MinimumGroundFlightOffset; //We cheat a bit and do a bit lower than normal if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude || (tempPos.Z - CAPSULE_LENGTH) < _parent_scene.GetTerrainHeightAtXY(tempPos.X + forwardVel.X, tempPos.Y + forwardVel.Y) + MinimumGroundFlightOffset) if (_target_velocity.Z < 0) vec.Z += (target_altitude - tempPos.Z)*PID_P*0.5f; //Don't apply so much else vec.Z += (target_altitude - tempPos.Z)*PID_P*1.05f; } else { //Straight up and down, only apply when they are very close to the ground float target_altitude = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y); if ((tempPos.Z - CAPSULE_LENGTH + (MinimumGroundFlightOffset/1.5)) < target_altitude + MinimumGroundFlightOffset) { if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude + 1) { vec.Z += ((target_altitude + 4) - (tempPos.Z - CAPSULE_LENGTH))*PID_P; } else vec.Z += ((target_altitude + MinimumGroundFlightOffset) - (tempPos.Z - CAPSULE_LENGTH))* PID_P*0.5f; } } #endregion } #region Gravity if (!flying) _parent_scene.CalculateGravity(m_mass, tempPos, true, 1.0f, ref gravForce); else _parent_scene.CalculateGravity(m_mass, tempPos, false, 0.65f, ref gravForce); //Allow point gravity and repulsors affect us a bit vec += gravForce; #endregion #region Under water physics if (_parent_scene.AllowUnderwaterPhysics && tempPos.X < _parent_scene.Region.RegionSizeX && tempPos.Y < _parent_scene.Region.RegionSizeY) { //Position plus height to av's shoulder (aprox) is just above water if ((tempPos.Z + (CAPSULE_LENGTH/3) - .25f) < _parent_scene.GetWaterLevel(tempPos.X, tempPos.Y)) { if (StartingUnderWater) ShouldBeWalking = Flying = false; StartingUnderWater = false; WasUnderWater = true; Flying = true; lastUnderwaterPush = 0; if (ShouldBeWalking) { lastUnderwaterPush += (float) (_parent_scene.GetWaterLevel(tempPos.X, tempPos.Y) - tempPos.Z)*33 + 3; vec.Z += lastUnderwaterPush; } else { lastUnderwaterPush += 3500; lastUnderwaterPush += (float) (_parent_scene.GetWaterLevel(tempPos.X, tempPos.Y) - tempPos.Z)*8; vec.Z += lastUnderwaterPush; } } else { StartingUnderWater = true; if (WasUnderWater) { WasUnderWater = false; Flying = true; } } } #endregion #endregion #region Apply the force if (IsFinite(vec)) { if (vec.X < 100000000 && vec.Y < 10000000 && vec.Z < 10000000) //Checks for crazy, going to NaN us values { // round small values to zero. those possible are just errors if (Math.Abs(vec.X) < 0.001) vec.X = 0; if (Math.Abs(vec.Y) < 0.001) vec.Y = 0; if (Math.Abs(vec.Z) < 0.001) vec.Z = 0; //ODE autodisables not moving prims, accept it and reenable when we need to if (!d.BodyIsEnabled(Body)) d.BodyEnable(Body); if (vec == Vector3.Zero) //if we arn't moving, STOP { if (m_lastForceApplied != -1) { m_lastForceApplied = -1; d.BodySetLinearVel(Body, vec.X, vec.Y, vec.Z); } } else { if (m_lastForceApplied < 5) vec *= m_lastForceApplied / 5; doForce(vec); m_lastForceApplied++; } // if (!_zeroFlag && (!flying || m_iscolliding)) // AlignAvatarTiltWithCurrentDirectionOfMovement (vec, gravForce); // the Amotor still lets avatar rotation to drift during colisions // so force it back to identity d.Quaternion qtmp; qtmp.W = 1; qtmp.X = 0; qtmp.Y = 0; qtmp.Z = 0; d.BodySetQuaternion(Body, ref qtmp); d.BodySetAngularVel(Body, 0, 0, 0); //When falling, we keep going faster and faster, and eventually, the client blue screens (blue is all you see). // The speed that does this is slightly higher than -30, so we cap it here so we never do that during falling. if (vel.Z < -30) { vel.Z = -30; d.BodySetLinearVel(Body, vel.X, vel.Y, vel.Z); } //Decay out the target velocity DON'T it forces tons of updates _target_velocity *= _parent_scene.m_avDecayTime; if (!_zeroFlag && _target_velocity.ApproxEquals (Vector3.Zero, _parent_scene.m_avStopDecaying)) _target_velocity = Vector3.Zero; } else { //This is a safe guard from going NaN, but it isn't very smooth... which is ok d.BodySetForce(Body, 0, 0, 0); d.BodySetLinearVel(Body, 0, 0, 0); } } else { MainConsole.Instance.Warn("[PHYSICS]: Got a NaN force vector in Move()"); MainConsole.Instance.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); Shell = IntPtr.Zero; } } #endregion }