From 652bcf91d50898181638a2668c9e2dcacfa33005 Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Thu, 25 Jun 2009 07:39:48 +0000 Subject: [PATCH] - fixes a "collection out of sync" exception in the ODE physics engine, caused by an "avatar infinite position" occurring under heavy load. - fixes "value too small" exception in ChatModule --- .../CoreModules/Avatar/Chat/ChatModule.cs | 4 +- .../Region/Physics/OdePlugin/ODECharacter.cs | 12 ++- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 77 +++++++++++-------- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 2814e92af3..dba6b38ddb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -294,8 +294,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); - int dis = Math.Abs((int) Util.GetDistanceTo(toRegionPos, fromRegionPos)); - + int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); + if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || type == ChatTypeEnum.Say && dis > m_saydistance || type == ChatTypeEnum.Shout && dis > m_shoutdistance) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 3f0d6c148c..e5e7d071d2 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; using OpenMetaverse; using Ode.NET; @@ -785,7 +786,7 @@ namespace OpenSim.Region.Physics.OdePlugin /// This is the avatar's movement control + PID Controller /// /// - public void Move(float timeStep) + public void Move(float timeStep, List defects) { // no lock; for now it's only called from within Simulate() @@ -803,11 +804,14 @@ namespace OpenSim.Region.Physics.OdePlugin d.Vector3 localpos = d.BodyGetPosition(Body); PhysicsVector localPos = new PhysicsVector(localpos.X, localpos.Y, localpos.Z); + if (!PhysicsVector.isFinite(localPos)) { m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); - _parent_scene.RemoveCharacter(this); + defects.Add(this); + // _parent_scene.RemoveCharacter(this); + // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { @@ -815,6 +819,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } + //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); @@ -958,7 +963,8 @@ namespace OpenSim.Region.Physics.OdePlugin { m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()"); m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); - _parent_scene.RemoveCharacter(this); + defects.Add(this); + // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 46689eb780..0f92358763 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -1434,42 +1434,45 @@ namespace OpenSim.Region.Physics.OdePlugin { _perloopContact.Clear(); - foreach (OdeCharacter chr in _characters) + lock (_characters) { - // Reset the collision values to false - // since we don't know if we're colliding yet - - // For some reason this can happen. Don't ask... - // - if (chr == null) - continue; - - if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) - continue; - - chr.IsColliding = false; - chr.CollidingGround = false; - chr.CollidingObj = false; - - // test the avatar's geometry for collision with the space - // This will return near and the space that they are the closest to - // And we'll run this again against the avatar and the space segment - // This will return with a bunch of possible objects in the space segment - // and we'll run it again on all of them. - try + foreach (OdeCharacter chr in _characters) { - d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); - } - catch (AccessViolationException) - { - m_log.Warn("[PHYSICS]: Unable to space collide"); - } - //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); - //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) - //{ + // Reset the collision values to false + // since we don't know if we're colliding yet + + // For some reason this can happen. Don't ask... + // + if (chr == null) + continue; + + if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) + continue; + + chr.IsColliding = false; + chr.CollidingGround = false; + chr.CollidingObj = false; + + // test the avatar's geometry for collision with the space + // This will return near and the space that they are the closest to + // And we'll run this again against the avatar and the space segment + // This will return with a bunch of possible objects in the space segment + // and we'll run it again on all of them. + try + { + d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); + } + catch (AccessViolationException) + { + m_log.Warn("[PHYSICS]: Unable to space collide"); + } + //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); + //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) + //{ //chr.Position.Z = terrainheight + 10.0f; //forcedZ = true; - //} + //} + } } lock (_activeprims) @@ -2799,10 +2802,18 @@ namespace OpenSim.Region.Physics.OdePlugin // Move characters lock (_characters) { + List defects = new List(); foreach (OdeCharacter actor in _characters) { if (actor != null) - actor.Move(timeStep); + actor.Move(timeStep, defects); + } + if (0 != defects.Count) + { + foreach (OdeCharacter defect in defects) + { + RemoveCharacter(defect); + } } }