private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
        {
            if (ContactgeomsArray == IntPtr.Zero || index >= contactsPerCollision)
            {
                return(false);
            }

            IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (index * d.ContactGeom.unmanagedSizeOf));

            newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
            return(true);
        }
        // This is the standard Near.   Uses space AABBs to speed up detection.
        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            //Don't test against heightfield Geom, or you'll be sorry!

            /*
             * terminate called after throwing an instance of 'std::bad_alloc'
             *    what():  std::bad_alloc
             *  Stacktrace:
             *
             *    at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
             *    at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
             *    at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
             *    at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
             *  fffff>
             *    at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
             *    at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
             *    at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
             *  0x00114>
             *    at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
             *    at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
             *    at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
             *    at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
             *    at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
             *    at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
             *
             *  Native stacktrace:
             *
             *          mono [0x80d2a42]
             *          [0xb7f5840c]
             *          /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
             *          /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
             *          /usr/lib/libstdc++.so.6 [0xb45fa865]
             *          /usr/lib/libstdc++.so.6 [0xb45fa8a2]
             *          /usr/lib/libstdc++.so.6 [0xb45fa9da]
             *          /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
             *          /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
             *          libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
             *          libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
             *          libode.so(dCollide+0x102) [0xb46571b2]
             *          [0x95cfdec9]
             *          [0x8ea07fe1]
             *          [0xab260146]
             *          libode.so [0xb465a5c4]
             *          libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
             *          libode.so(dSpaceCollide2+0x177) [0xb465ac67]
             *          [0x95cf978e]
             *          [0x8ea07945]
             *          [0x95cf2bbc]
             *          [0xab2787e7]
             *          [0xab419fb3]
             *          [0xab416657]
             *          [0xab415bda]
             *          [0xb609b08e]
             *          mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
             *          mono [0x81a2f0f]
             *          mono [0x81d28b6]
             *          mono [0x81ea2c6]
             *          /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
             *          /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
             */

            // Exclude heightfield geom

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
            {
                return;
            }
            if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass ||
                d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
            {
                return;
            }

            // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
            if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
            {
                if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                {
                    return;
                }

                // 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 (AccessViolationException)
                {
                    MainConsole.Instance.Warn("[PHYSICS]: Unable to collide test a space");
                    return;
                }
                //Colliding a space or a geom with a space or a geom. so drill down

                //Collide all geoms in each space..
                //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
                //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
                return;
            }

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
            {
                return;
            }

            int count = 0;

            try
            {
                if (g1 == g2)
                {
                    return; // Can't collide with yourself
                }
                count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray,
                                     d.ContactGeom.unmanagedSizeOf);
            }
            catch (SEHException)
            {
                MainConsole.Instance.Error(
                    "[PHYSICS]: The Operating system shut down ODE because of corrupt memory.  This could be a result of really irregular terrain.  If this repeats continuously, restart using Basic Physics and terrain fill your terrain.  Restarting the sim.");
            }
            catch (Exception e)
            {
                MainConsole.Instance.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e);
                return;
            }

            PhysicsActor p1 = null;

            if (g1 != IntPtr.Zero)
            {
                m_scene.actor_name_map.TryGetValue(g1, out p1);
            }

            // Loop over contacts, build results.
            d.ContactGeom curContact = new d.ContactGeom();
            for (int i = 0; i < count; i++)
            {
                if (!GetCurContactGeom(i, ref curContact))
                {
                    break;
                }

                if (p1 != null)
                {
                    if (p1 is AuroraODEPrim)
                    {
                        ContactResult collisionresult = new ContactResult
                        {
                            ConsumerID = ((AuroraODEPrim)p1).LocalID,
                            Pos        =
                                new Vector3(curContact.pos.X, curContact.pos.Y,
                                            curContact.pos.Z),
                            Depth  = curContact.depth,
                            Normal =
                                new Vector3(curContact.normal.X,
                                            curContact.normal.Y,
                                            curContact.normal.Z)
                        };

                        lock (m_contactResults)
                            m_contactResults.Add(collisionresult);
                    }
                }
            }
        }
        /// <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);
        }
        // This is the standard Near.   Uses space AABBs to speed up detection.
        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            //Don't test against heightfield Geom, or you'll be sorry!

            /*
             terminate called after throwing an instance of 'std::bad_alloc'
                  what():  std::bad_alloc
                Stacktrace:

                  at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
                  at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
                  at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
                  at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
                fffff>
                  at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
                  at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
                  at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
                0x00114>
                  at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
                  at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
                  at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
                  at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
                  at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
                  at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>

                Native stacktrace:

                        mono [0x80d2a42]
                        [0xb7f5840c]
                        /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
                        /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
                        /usr/lib/libstdc++.so.6 [0xb45fa865]
                        /usr/lib/libstdc++.so.6 [0xb45fa8a2]
                        /usr/lib/libstdc++.so.6 [0xb45fa9da]
                        /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
                        /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
                        libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
                        libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
                        libode.so(dCollide+0x102) [0xb46571b2]
                        [0x95cfdec9]
                        [0x8ea07fe1]
                        [0xab260146]
                        libode.so [0xb465a5c4]
                        libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
                        libode.so(dSpaceCollide2+0x177) [0xb465ac67]
                        [0x95cf978e]
                        [0x8ea07945]
                        [0x95cf2bbc]
                        [0xab2787e7]
                        [0xab419fb3]
                        [0xab416657]
                        [0xab415bda]
                        [0xb609b08e]
                        mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
                        mono [0x81a2f0f]
                        mono [0x81d28b6]
                        mono [0x81ea2c6]
                        /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
                        /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
             */

            // Exclude heightfield geom

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                return;
            if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass ||
                d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
                return;

            // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
            if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
            {
                if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                    return;

                // 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 (AccessViolationException)
                {
                    MainConsole.Instance.Warn("[PHYSICS]: Unable to collide test a space");
                    return;
                }
                //Colliding a space or a geom with a space or a geom. so drill down

                //Collide all geoms in each space..
                //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
                //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
                return;
            }

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                return;

            int count = 0;
            try
            {
                if (g1 == g2)
                    return; // Can't collide with yourself

                count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray,
                                        d.ContactGeom.unmanagedSizeOf);
            }
            catch (SEHException)
            {
                MainConsole.Instance.Error(
                    "[PHYSICS]: The Operating system shut down ODE because of corrupt memory.  This could be a result of really irregular terrain.  If this repeats continuously, restart using Basic Physics and terrain fill your terrain.  Restarting the sim.");
            }
            catch (Exception e)
            {
                MainConsole.Instance.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e);
                return;
            }

            PhysicsActor p1 = null;

            if (g1 != IntPtr.Zero)
                m_scene.actor_name_map.TryGetValue(g1, out p1);

            // Loop over contacts, build results.
            d.ContactGeom curContact = new d.ContactGeom();
            for (int i = 0; i < count; i++)
            {
                if (!GetCurContactGeom(i, ref curContact))
                    break;

                if (p1 != null)
                {
                    if (p1 is WhiteCoreODEPrim)
                    {
                        ContactResult collisionresult = new ContactResult
                                                            {
                                                                ConsumerID = ((WhiteCoreODEPrim) p1).LocalID,
                                                                Pos =
                                                                    new Vector3(curContact.pos.X, curContact.pos.Y,
                                                                                curContact.pos.Z),
                                                                Depth = curContact.depth,
                                                                Normal =
                                                                    new Vector3(curContact.normal.X,
                                                                                curContact.normal.Y,
                                                                                curContact.normal.Z)
                                                            };

                        lock (m_contactResults)
                            m_contactResults.Add(collisionresult);
                    }
                }
            }
        }
        /// <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 || !ContinueCollisionProcessing)
                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 WhiteCoreODEPrim)
                        RemovePrim((WhiteCoreODEPrim) badObj);
                    else if (badObj is WhiteCoreODECharacter)
                        RemoveAvatar((WhiteCoreODECharacter) badObj);
                if (actor_name_map.TryGetValue(g2, out badObj))
                    if (badObj is WhiteCoreODEPrim)
                        RemovePrim((WhiteCoreODEPrim) badObj);
                    else if (badObj is WhiteCoreODECharacter)
                        RemoveAvatar((WhiteCoreODECharacter) 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();
            // 20131224 not used            d.ContactGeom maxContact = 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;
            // 20131224 not used                    maxContact = curContact;
                }
            }
            if (p1 is WhiteCoreODECharacter || p2 is WhiteCoreODECharacter)
                //This really should be maxContact, but there are crashes that users have reported when this is used...
                //AddODECollision(maxContact, p1, p2, b1, b2, maxDepthContact, ref NotSkipedCount);
                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);
            } //);
        }
        // This is the standard Near. g1 is the ray
        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            if (g2 == IntPtr.Zero || g1 == g2)
            {
                return;
            }

            if (m_contactResults.Count >= CurrentMaxCount)
            {
                return;
            }

            if (d.GeomIsSpace(g2))
            {
                try
                {
                    d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
                }
                catch (Exception e)
                {
                    m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
                }
                return;
            }

            int count = 0;

            try
            {
                count = d.CollidePtr(g1, g2, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
            }
            catch (Exception e)
            {
                m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
                return;
            }

            if (count == 0)
            {
                return;
            }

/*
 *          uint cat1 = d.GeomGetCategoryBits(g1);
 *          uint cat2 = d.GeomGetCategoryBits(g2);
 *          uint col1 = d.GeomGetCollideBits(g1);
 *          uint col2 = d.GeomGetCollideBits(g2);
 */

            uint         ID = 0;
            PhysicsActor p2 = null;

            m_scene.actor_name_map.TryGetValue(g2, out p2);

            if (p2 == null)
            {
                return;
            }

            switch (p2.PhysicsActorType)
            {
            case (int)ActorTypes.Prim:

                RayFilterFlags thisFlags;

                if (p2.IsPhysical)
                {
                    thisFlags = RayFilterFlags.physical;
                }
                else
                {
                    thisFlags = RayFilterFlags.nonphysical;
                }

                if (p2.Phantom)
                {
                    thisFlags |= RayFilterFlags.phantom;
                }

                if (p2.IsVolumeDtc)
                {
                    thisFlags |= RayFilterFlags.volumedtc;
                }

                if ((thisFlags & CurrentRayFilter) == 0)
                {
                    return;
                }

                ID = ((OdePrim)p2).LocalID;
                break;

            case (int)ActorTypes.Agent:

                if ((CurrentRayFilter & RayFilterFlags.agent) == 0)
                {
                    return;
                }
                else
                {
                    ID = ((OdeCharacter)p2).LocalID;
                }
                break;

            case (int)ActorTypes.Ground:

                if ((CurrentRayFilter & RayFilterFlags.land) == 0)
                {
                    return;
                }
                break;

            case (int)ActorTypes.Water:

                if ((CurrentRayFilter & RayFilterFlags.water) == 0)
                {
                    return;
                }
                break;

            default:
                break;
            }

            d.ContactGeom curcontact = new d.ContactGeom();

            // closestHit for now only works for meshs, so must do it for others
            if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
            {
                // Loop all contacts, build results.
                for (int i = 0; i < count; i++)
                {
                    if (!GetCurContactGeom(i, ref curcontact))
                    {
                        break;
                    }

                    ContactResult collisionresult = new ContactResult();
                    collisionresult.ConsumerID = ID;
                    collisionresult.Pos.X      = curcontact.pos.X;
                    collisionresult.Pos.Y      = curcontact.pos.Y;
                    collisionresult.Pos.Z      = curcontact.pos.Z;
                    collisionresult.Depth      = curcontact.depth;
                    collisionresult.Normal.X   = curcontact.normal.X;
                    collisionresult.Normal.Y   = curcontact.normal.Y;
                    collisionresult.Normal.Z   = curcontact.normal.Z;
                    lock (m_contactResults)
                    {
                        m_contactResults.Add(collisionresult);
                        if (m_contactResults.Count >= CurrentMaxCount)
                        {
                            return;
                        }
                    }
                }
            }
            else
            {
                // keep only closest contact
                ContactResult collisionresult = new ContactResult();
                collisionresult.ConsumerID = ID;
                collisionresult.Depth      = float.MaxValue;

                for (int i = 0; i < count; i++)
                {
                    if (!GetCurContactGeom(i, ref curcontact))
                    {
                        break;
                    }

                    if (curcontact.depth < collisionresult.Depth)
                    {
                        collisionresult.Pos.X    = curcontact.pos.X;
                        collisionresult.Pos.Y    = curcontact.pos.Y;
                        collisionresult.Pos.Z    = curcontact.pos.Z;
                        collisionresult.Depth    = curcontact.depth;
                        collisionresult.Normal.X = curcontact.normal.X;
                        collisionresult.Normal.Y = curcontact.normal.Y;
                        collisionresult.Normal.Z = curcontact.normal.Z;
                    }
                }

                if (collisionresult.Depth != float.MaxValue)
                {
                    lock (m_contactResults)
                        m_contactResults.Add(collisionresult);
                }
            }
        }
        // This is the standard Near.   Uses space AABBs to speed up detection.
        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            //Don't test against heightfield Geom, or you'll be sorry!

            // Exclude heightfield geom

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
            {
                return;
            }
            if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass ||
                d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
            {
                return;
            }

            // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
            if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
            {
                if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                {
                    return;
                }

                // 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 (AccessViolationException)
                {
                    MainConsole.Instance.Warn("[PHYSICS]: Unable to collide test a space");
                    return;
                }

                return;
            }

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
            {
                return;
            }

            int count = 0;

            try
            {
                if (g1 == g2)
                {
                    return; // Can't collide with yourself
                }
                count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray,
                                     d.ContactGeom.unmanagedSizeOf);
            }
            catch (SEHException)
            {
                MainConsole.Instance.Error(
                    "[PHYSICS]: The Operating system shut down ODE because of corrupt memory.  This could be a result of really irregular terrain.  If this repeats continuously, restart using Basic Physics and terrain fill your terrain.  Restarting the sim.");
            }
            catch (Exception e)
            {
                MainConsole.Instance.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e);
                return;
            }

            PhysicsActor p1 = null;

            if (g1 != IntPtr.Zero)
            {
                m_scene.actor_name_map.TryGetValue(g1, out p1);
            }

            // Loop over contacts, build results.
            d.ContactGeom curContact = new d.ContactGeom();
            for (int i = 0; i < count; i++)
            {
                if (!GetCurContactGeom(i, ref curContact))
                {
                    break;
                }

                if (p1 != null)
                {
                    if (p1 is AuroraODEPrim)
                    {
                        ContactResult collisionresult = new ContactResult
                        {
                            ConsumerID = ((AuroraODEPrim)p1).LocalID,
                            Pos        =
                                new Vector3(curContact.pos.X, curContact.pos.Y,
                                            curContact.pos.Z),
                            Depth  = curContact.depth,
                            Normal =
                                new Vector3(curContact.normal.X,
                                            curContact.normal.Y,
                                            curContact.normal.Z)
                        };

                        lock (m_contactResults)
                            m_contactResults.Add(collisionresult);
                    }
                }
            }
        }