public void MoveObject(ulong id, BoundingBoxD aabb, Vector3 velocity)
 {
     using (this.m_clustersLock.AcquireExclusiveUsing())
     {
         MyObjectData data;
         if (this.m_objectsData.TryGetValue(id, out data))
         {
             BoundingBoxD aABB = data.AABB;
             data.AABB = aabb;
             if (!this.m_suppressClusterReorder)
             {
                 aabb = AdjustAABBByVelocity(aabb, velocity, 0f);
                 ContainmentType type = data.Cluster.AABB.Contains(aabb);
                 if (((type != ContainmentType.Contains) && !this.SingleCluster.HasValue) && !this.ForcedClusters)
                 {
                     if (type == ContainmentType.Disjoint)
                     {
                         this.m_clusterTree.OverlapAllBoundingBox <MyCluster>(ref aabb, this.m_returnedClusters, 0, true);
                         if ((this.m_returnedClusters.Count == 1) && (this.m_returnedClusters[0].AABB.Contains(aabb) == ContainmentType.Contains))
                         {
                             MyCluster cluster = data.Cluster;
                             this.RemoveObjectFromCluster(data, false);
                             if (cluster.Objects.Count == 0)
                             {
                                 this.RemoveCluster(cluster);
                             }
                             this.AddObjectToCluster(this.m_returnedClusters[0], data.Id, false);
                         }
                         else
                         {
                             aabb.InflateToMinimum(IdealClusterSize);
                             this.ReorderClusters(aabb.Include(aABB), id);
                         }
                     }
                     else
                     {
                         aabb.InflateToMinimum(IdealClusterSize);
                         this.ReorderClusters(aabb.Include(aABB), id);
                     }
                 }
             }
         }
     }
 }
        // Iterate over sector boxes in a range.
        // TODO: Dumb version of this for small boxes
        private unsafe void RasterSectorsForPhysics(BoundingBoxD range)
        {
            range.InflateToMinimum(EnvironmentDefinition.SectorSize);

            Vector2I top = new Vector2I(1 << m_clipmaps[0].Depth) - 1;

            Vector3D* pos = stackalloc Vector3D[8];

            range.GetCornersUnsafe(pos);

            // bitmask for faces, 7th bit is simple bit
            int markedFaces = 0;
            int firstFace = 0;

            for (var i = 0; i < 8; ++i)
            {
                Vector3D copy = pos[i];

                int index = MyPlanetCubemapHelper.FindCubeFace(ref copy);
                firstFace = index;
                index = 1 << index;

                if ((markedFaces & ~index) != 0) markedFaces |= 0x40;

                markedFaces |= index;
            }

            // This way we can ensure a single code path.
            int startFace = 0;
            int endFace = 5;

            // If we only encounter one face we narrow it down.
            if ((markedFaces & 0x40) == 0)
            {
                startFace = endFace = firstFace;
            }

            for (int face = startFace; face <= endFace; ++face)
            {
                if (((1 << face) & markedFaces) == 0)
                    continue;

                double size = m_clipmaps[face].LeafSize;

                // Offset 
                var offset = 1 << m_clipmaps[face].Depth - 1;

                BoundingBox2D bounds = BoundingBox2D.CreateInvalid();
                for (int i = 0; i < 8; ++i)
                {
                    Vector3D copy = pos[i];

                    Vector2D normCoords;
                    MyPlanetCubemapHelper.ProjectForFace(ref copy, face, out normCoords);
                    bounds.Include(normCoords);
                }

                bounds.Min += 1;
                bounds.Min *= offset;

                bounds.Max += 1;
                bounds.Max *= offset;

                // Calculate bounds in sectors.
                var start = new Vector2I((int)bounds.Min.X, (int)bounds.Min.Y);
                var end = new Vector2I((int)bounds.Max.X, (int)bounds.Max.Y);

                Vector2I.Max(ref start, ref Vector2I.Zero, out start);
                Vector2I.Min(ref end, ref top, out end);

                for (int x = start.X; x <= end.X; ++x)
                    for (int y = start.Y; y <= end.Y; ++y)
                    {
                        EnsurePhysicsSector(x, y, face);
                    }
            }
        }
        // Iterate over sector boxes in a range.
        // TODO: Dumb version of this for small boxes
        private unsafe void RasterSectorsForPhysics(BoundingBoxD range)
        {
            range.InflateToMinimum(EnvironmentDefinition.SectorSize);

            Vector2I top = new Vector2I(1 << m_clipmaps[0].Depth) - 1;

            Vector3D *pos = stackalloc Vector3D[8];

            range.GetCornersUnsafe(pos);

            // bitmask for faces, 7th bit is simple bit
            int markedFaces = 0;
            int firstFace   = 0;

            for (var i = 0; i < 8; ++i)
            {
                Vector3D copy = pos[i];

                int index = MyPlanetCubemapHelper.FindCubeFace(ref copy);
                firstFace = index;
                index     = 1 << index;

                if ((markedFaces & ~index) != 0)
                {
                    markedFaces |= 0x40;
                }

                markedFaces |= index;
            }

            // This way we can ensure a single code path.
            int startFace = 0;
            int endFace   = 5;

            // If we only encounter one face we narrow it down.
            if ((markedFaces & 0x40) == 0)
            {
                startFace = endFace = firstFace;
            }

            for (int face = startFace; face <= endFace; ++face)
            {
                if (((1 << face) & markedFaces) == 0)
                {
                    continue;
                }

                double size = m_clipmaps[face].LeafSize;

                // Offset
                var offset = 1 << m_clipmaps[face].Depth - 1;

                BoundingBox2D bounds = BoundingBox2D.CreateInvalid();
                for (int i = 0; i < 8; ++i)
                {
                    Vector3D copy = pos[i];

                    Vector2D normCoords;
                    MyPlanetCubemapHelper.ProjectForFace(ref copy, face, out normCoords);
                    bounds.Include(normCoords);
                }

                bounds.Min += 1;
                bounds.Min *= offset;

                bounds.Max += 1;
                bounds.Max *= offset;

                // Calculate bounds in sectors.
                var start = new Vector2I((int)bounds.Min.X, (int)bounds.Min.Y);
                var end   = new Vector2I((int)bounds.Max.X, (int)bounds.Max.Y);

                Vector2I.Max(ref start, ref Vector2I.Zero, out start);
                Vector2I.Min(ref end, ref top, out end);

                for (int x = start.X; x <= end.X; ++x)
                {
                    for (int y = start.Y; y <= end.Y; ++y)
                    {
                        EnsurePhysicsSector(x, y, face);
                    }
                }
            }
        }
        //1. Object A reaches borders
        //2. Make ideal cluster box B around A
        //3. Detect all cluster intersections C of B
        //4. Make union of all C and B to D
        //5. Find best division of D
        //6. Foreach dominant axis
        //6A  split until only allowed size
        //6B  leave lowest larger size
        //repeat 6 until dominant axis is allowed size or not splittable
        public void ReorderClusters(BoundingBoxD aabb, ulong objectId)
        {
            //1+2
            aabb.InflateToMinimum(IdealClusterSize);

            bool         isBoxSafe    = false;
            BoundingBoxD unionCluster = aabb;

            //3
            m_clusterTree.OverlapAllBoundingBox(ref unionCluster, m_resultList);
            HashSet <MyObjectData> objectsInUnion = new HashSet <MyObjectData>();

            while (!isBoxSafe)
            {
                //4
                objectsInUnion.Clear();
                objectsInUnion.Add(m_objectsData[objectId]);

                foreach (MyCluster collidedCluster in m_resultList)
                {
                    unionCluster.Include(collidedCluster.AABB);
                    foreach (var ob in m_objectsData.Where(x => collidedCluster.Objects.Contains(x.Key)).Select(x => x.Value))
                    {
                        objectsInUnion.Add(ob);
                    }
                }

                int oldClustersCount = m_resultList.Count;
                //3
                m_clusterTree.OverlapAllBoundingBox(ref unionCluster, m_resultList);

                isBoxSafe = oldClustersCount == m_resultList.Count; //Box is safe only if no new clusters were added

                m_staticTree.OverlapAllBoundingBox(ref unionCluster, m_objectDataResultList);
                foreach (var ob in m_objectDataResultList)
                {
                    if (m_objectsData[ob].Cluster != null)
                    {
                        if (!m_resultList.Contains(m_objectsData[ob].Cluster))
                        {
                            unionCluster.Include(m_objectsData[ob].Cluster.AABB);
                            isBoxSafe = false;
                        }
                    }
                }
            }

            m_staticTree.OverlapAllBoundingBox(ref unionCluster, m_objectDataResultList);
            foreach (var ob in m_objectDataResultList)
            {
                //var c = m_objectsData[ob].Cluster.AABB.Contains(unionCluster);
                System.Diagnostics.Debug.Assert(m_objectsData[ob].Cluster == null || m_objectsData[ob].Cluster.AABB.Contains(m_objectsData[ob].AABB) != ContainmentType.Disjoint, "Clusters failure");
                System.Diagnostics.Debug.Assert(m_objectsData[ob].Cluster == null || (m_clusters.Contains(m_objectsData[ob].Cluster) && m_resultList.Contains(m_objectsData[ob].Cluster)), "Static object is not inside found clusters");
                objectsInUnion.Add(m_objectsData[ob]);
            }

#if DEBUG
            foreach (var ob in objectsInUnion)
            {
                System.Diagnostics.Debug.Assert(ob.Cluster == null || (m_clusters.Contains(ob.Cluster) && m_resultList.Contains(ob.Cluster)), "There is object not belonging to found cluster!");
            }
#endif

            //5
            Stack <MyClusterDescription> clustersToDivide = new Stack <MyClusterDescription>();
            List <MyClusterDescription>  finalClusters    = new List <MyClusterDescription>();

            var unionClusterDesc = new MyClusterDescription()
            {
                AABB           = unionCluster,
                DynamicObjects = objectsInUnion.Where(x => x.ActivationHandler == null || !x.ActivationHandler.IsStaticForCluster).ToList(),
                StaticObjects  = objectsInUnion.Where(x => (x.ActivationHandler != null) && x.ActivationHandler.IsStaticForCluster).ToList(),
            };
            clustersToDivide.Push(unionClusterDesc);

            var staticObjectsToRemove = unionClusterDesc.StaticObjects.Where(x => x.Cluster != null).ToList();
            var staticObjectsTotal    = unionClusterDesc.StaticObjects.Count;


            while (clustersToDivide.Count > 0)
            {
                MyClusterDescription desc = clustersToDivide.Pop();

                if (desc.DynamicObjects.Count == 0)
                {
                    continue;
                }

                //minimal valid aabb usable for this cluster
                BoundingBoxD minimumCluster = BoundingBoxD.CreateInvalid();
                for (int i = 0; i < desc.DynamicObjects.Count; i++)
                {
                    MyObjectData objectData0 = desc.DynamicObjects[i];
                    BoundingBoxD aabb0       = objectData0.AABB.GetInflated(IdealClusterSize / 2);
                    minimumCluster.Include(aabb0);
                }

                //Divide along longest axis
                BoundingBoxD dividedCluster = minimumCluster;

                Vector3D currentMax  = minimumCluster.Max;
                int      longestAxis = minimumCluster.Size.AbsMaxComponent();

                switch (longestAxis)
                {
                case 0:
                    desc.DynamicObjects.Sort(AABBComparerX.Static);
                    break;

                case 1:
                    desc.DynamicObjects.Sort(AABBComparerY.Static);
                    break;

                case 2:
                    desc.DynamicObjects.Sort(AABBComparerZ.Static);
                    break;
                }

                bool isClusterSplittable = false;

                if (minimumCluster.Size.AbsMax() >= MaximumForSplit.AbsMax())
                {
                    for (int i = 1; i < desc.DynamicObjects.Count; i++)
                    {
                        MyObjectData objectData0 = desc.DynamicObjects[i - 1];
                        MyObjectData objectData1 = desc.DynamicObjects[i];

                        BoundingBoxD aabb0 = objectData0.AABB.GetInflated(IdealClusterSize / 2);
                        BoundingBoxD aabb1 = objectData1.AABB.GetInflated(IdealClusterSize / 2);

                        //two neigbour object have distance between them bigger than minimum
                        if ((aabb1.Min.GetDim(longestAxis) - aabb0.Max.GetDim(longestAxis)) > 0)
                        {
                            System.Diagnostics.Debug.Assert(aabb0.Max.GetDim(longestAxis) - minimumCluster.Min.GetDim(longestAxis) > 0, "Invalid minimal cluster");
                            isClusterSplittable = true;

                            currentMax.SetDim(longestAxis, aabb0.Max.GetDim(longestAxis));

                            break;
                        }
                    }
                }

                dividedCluster.Max = currentMax;

                dividedCluster.InflateToMinimum(IdealClusterSize);

                MyClusterDescription dividedClusterDesc = new MyClusterDescription()
                {
                    AABB           = dividedCluster,
                    DynamicObjects = new List <MyObjectData>(),
                    StaticObjects  = new List <MyObjectData>(),
                };

                foreach (var dynObj in desc.DynamicObjects.ToList())
                {
                    var cont = dividedCluster.Contains(dynObj.AABB);
                    if (cont == ContainmentType.Contains)
                    {
                        dividedClusterDesc.DynamicObjects.Add(dynObj);
                        desc.DynamicObjects.Remove(dynObj);
                    }

                    System.Diagnostics.Debug.Assert(cont != ContainmentType.Intersects, "Cannot split clusters in the middle of objects");
                }
                foreach (var statObj in desc.StaticObjects.ToList())
                {
                    var cont = dividedCluster.Contains(statObj.AABB);
                    if ((cont == ContainmentType.Contains) || (cont == ContainmentType.Intersects))
                    {
                        dividedClusterDesc.StaticObjects.Add(statObj);
                        desc.StaticObjects.Remove(statObj);
                    }
                }

                dividedClusterDesc.AABB = dividedCluster;

                if (desc.DynamicObjects.Count > 0)
                {
                    BoundingBoxD restCluster = BoundingBoxD.CreateInvalid();

                    foreach (var restbb in desc.DynamicObjects)
                    {
                        restCluster.Include(restbb.AABB.GetInflated(MinimumDistanceFromBorder));
                    }

                    restCluster.InflateToMinimum(IdealClusterSize);

                    MyClusterDescription restClusterDesc = new MyClusterDescription()
                    {
                        AABB           = restCluster,
                        DynamicObjects = desc.DynamicObjects.ToList(),
                        StaticObjects  = desc.StaticObjects.ToList(),
                    };

                    if (restClusterDesc.AABB.Size.AbsMax() > 2 * IdealClusterSize.AbsMax())
                    {
                        clustersToDivide.Push(restClusterDesc);
                    }
                    else
                    {
                        finalClusters.Add(restClusterDesc);
                    }
                }

                if (dividedClusterDesc.AABB.Size.AbsMax() > 2 * IdealClusterSize.AbsMax() && isClusterSplittable)
                {
                    clustersToDivide.Push(dividedClusterDesc);
                }
                else
                {
                    finalClusters.Add(dividedClusterDesc);
                }
            }

#if DEBUG
            //Check consistency
            for (int i = 0; i < finalClusters.Count; i++)
            {
                for (int j = 0; j < finalClusters.Count; j++)
                {
                    if (i != j)
                    {
                        var cont = finalClusters[i].AABB.Contains(finalClusters[j].AABB);
                        System.Diagnostics.Debug.Assert(cont == ContainmentType.Disjoint, "Overlapped clusters!");
                        if (cont != ContainmentType.Disjoint)
                        {
                        }
                    }
                }
            }
#endif

#if DEBUG
            Dictionary <MyCluster, List <ulong> > objectsPerRemovedCluster = new Dictionary <MyCluster, List <ulong> >();
            Dictionary <MyCluster, List <ulong> > dynamicObjectsInCluster  = new Dictionary <MyCluster, List <ulong> >();
            foreach (var finalCluster in finalClusters)
            {
                foreach (var ob in finalCluster.DynamicObjects)
                {
                    if (ob.Cluster != null)
                    {
                        if (!objectsPerRemovedCluster.ContainsKey(ob.Cluster))
                        {
                            objectsPerRemovedCluster[ob.Cluster] = new List <ulong>();
                        }

                        objectsPerRemovedCluster[ob.Cluster].Add(ob.Id);
                    }
                    else
                    {
                    }
                }
            }

            foreach (var removingCluster in objectsPerRemovedCluster)
            {
                dynamicObjectsInCluster[removingCluster.Key] = new List <ulong>();
                foreach (var ob in removingCluster.Key.Objects)
                {
                    if (!m_objectsData[ob].ActivationHandler.IsStaticForCluster)
                    {
                        dynamicObjectsInCluster[removingCluster.Key].Add(ob);
                    }
                }

                System.Diagnostics.Debug.Assert(removingCluster.Value.Count == dynamicObjectsInCluster[removingCluster.Key].Count, "Not all objects from removing cluster are going to new clusters!");
            }

            Dictionary <MyCluster, List <ulong> > staticObjectsInCluster = new Dictionary <MyCluster, List <ulong> >();
            foreach (var staticObj in staticObjectsToRemove)
            {
                System.Diagnostics.Debug.Assert(staticObj.Cluster != null, "Where to remove?");
                if (!staticObjectsInCluster.ContainsKey(staticObj.Cluster))
                {
                    staticObjectsInCluster[staticObj.Cluster] = new List <ulong>();
                }

                staticObjectsInCluster[staticObj.Cluster].Add(staticObj.Id);
            }
#endif

            HashSet <MyCluster> oldClusters = new HashSet <MyCluster>();
            HashSet <MyCluster> newClusters = new HashSet <MyCluster>();

            foreach (var staticObj in staticObjectsToRemove)
            {
                if (staticObj.Cluster != null)
                {
                    oldClusters.Add(staticObj.Cluster);
                    RemoveObjectFromCluster(staticObj, true);
                }
                else
                {
                }
            }

            foreach (var staticObj in staticObjectsToRemove)
            {
                if (staticObj.Cluster != null)
                {
                    staticObj.ActivationHandler.FinishRemoveBatch(staticObj.Cluster.UserData);
                    staticObj.Cluster = null;
                }
            }

            int staticObjectsAdded = 0;

            //Move objects from old clusters to new clusters, use batching
            foreach (var finalCluster in finalClusters)
            {
                BoundingBoxD clusterAABB = finalCluster.AABB;
                MyCluster    newCluster  = CreateCluster(ref clusterAABB);

#if DEBUG
                for (int i = 0; i < finalCluster.DynamicObjects.Count; i++)
                {
                    for (int j = 0; j < finalCluster.DynamicObjects.Count; j++)
                    {
                        if (i != j)
                        {
                            System.Diagnostics.Debug.Assert(finalCluster.DynamicObjects[i].Id != finalCluster.DynamicObjects[j].Id);
                        }
                    }
                }
#endif

                foreach (var obj in finalCluster.DynamicObjects)
                {
                    if (obj.Cluster != null)
                    {
                        oldClusters.Add(obj.Cluster);
                        RemoveObjectFromCluster(obj, true);
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(objectId == obj.Id || obj.ActivationHandler.IsStaticForCluster, "Dynamic object must have cluster");
                    }
                }

                foreach (var obj in finalCluster.DynamicObjects)
                {
                    if (obj.Cluster != null)
                    {
                        obj.ActivationHandler.FinishRemoveBatch(obj.Cluster.UserData);
                        obj.Cluster = null;
                    }
                }

                //Finish batches on old worlds and remove old worlds
                foreach (MyCluster oldCluster in oldClusters)
                {
                    if (OnFinishBatch != null)
                    {
                        OnFinishBatch(oldCluster.UserData);
                    }
                }


                foreach (var obj in finalCluster.DynamicObjects)
                {
                    AddObjectToCluster(newCluster, obj.Id, true);
                }

                foreach (var obj in finalCluster.StaticObjects)
                {
                    if (newCluster.AABB.Contains(obj.AABB) != ContainmentType.Disjoint)
                    {
                        AddObjectToCluster(newCluster, obj.Id, true);
                        staticObjectsAdded++;
                    }
                }

                newClusters.Add(newCluster);
            }

            System.Diagnostics.Debug.Assert(staticObjectsTotal >= staticObjectsAdded, "Static objects appeared out of union");

#if DEBUG
            //foreach (var finalCluster in finalClusters)
            //{
            //    foreach (var obj in finalCluster.DynamicObjects)
            //    {
            //        System.Diagnostics.Debug.Assert(!oldClusters.Contains(obj.Cluster), "Object was not added to correct cluster");
            //    }
            //}

            //foreach (var objectData in m_objectsData)
            //{
            //    if (!objectData.Value.ActivationHandler.IsStaticForCluster)
            //        System.Diagnostics.Debug.Assert(!oldClusters.Contains(objectData.Value.Cluster));
            //}

            //foreach (var objectData in m_objectsData)
            //{
            //    if (!objectData.Value.ActivationHandler.IsStaticForCluster)
            //        System.Diagnostics.Debug.Assert(m_clusters.Contains(objectData.Value.Cluster));
            //}
#endif
            foreach (MyCluster oldCluster in oldClusters)
            {
                RemoveCluster(oldCluster);
            }

            //Finish batches on new world and their objects
            foreach (MyCluster newCluster in newClusters)
            {
                if (OnFinishBatch != null)
                {
                    OnFinishBatch(newCluster.UserData);
                }

                foreach (var ob in newCluster.Objects)
                {
                    if (m_objectsData[ob].ActivationHandler != null)
                    {
                        m_objectsData[ob].ActivationHandler.FinishAddBatch();
                    }
                }
            }
        }
        public void ReorderClusters(BoundingBoxD aabb, ulong objectId = 18446744073709551615L)
        {
            using (this.m_clustersReorderLock.AcquireExclusiveUsing())
            {
                aabb.InflateToMinimum(IdealClusterSize);
                bool         flag = false;
                BoundingBoxD bbox = aabb;
                this.m_clusterTree.OverlapAllBoundingBox <MyCluster>(ref bbox, m_resultList, 0, true);
                HashSet <MyObjectData> source = new HashSet <MyObjectData>();
                while (!flag)
                {
                    source.Clear();
                    if (objectId != ulong.MaxValue)
                    {
                        source.Add(this.m_objectsData[objectId]);
                    }
                    using (List <MyCluster> .Enumerator enumerator = m_resultList.GetEnumerator())
                    {
                        while (enumerator.MoveNext())
                        {
                            Func <KeyValuePair <ulong, MyObjectData>, bool> predicate = null;
                            MyCluster collidedCluster = enumerator.Current;
                            bbox.Include(collidedCluster.AABB);
                            if (predicate == null)
                            {
                                predicate = x => collidedCluster.Objects.Contains(x.Key);
                            }
                            foreach (MyObjectData data in from x in this.m_objectsData.Where <KeyValuePair <ulong, MyObjectData> >(predicate) select x.Value)
                            {
                                source.Add(data);
                            }
                        }
                    }
                    int num = m_resultList.Count;
                    this.m_clusterTree.OverlapAllBoundingBox <MyCluster>(ref bbox, m_resultList, 0, true);
                    flag = num == m_resultList.Count;
                    this.m_staticTree.OverlapAllBoundingBox <ulong>(ref bbox, m_objectDataResultList, 0, true);
                    foreach (ulong num2 in m_objectDataResultList)
                    {
                        if ((this.m_objectsData[num2].Cluster != null) && !m_resultList.Contains(this.m_objectsData[num2].Cluster))
                        {
                            bbox.Include(this.m_objectsData[num2].Cluster.AABB);
                            flag = false;
                        }
                    }
                }
                this.m_staticTree.OverlapAllBoundingBox <ulong>(ref bbox, m_objectDataResultList, 0, true);
                foreach (ulong num3 in m_objectDataResultList)
                {
                    source.Add(this.m_objectsData[num3]);
                }
                Stack <MyClusterDescription> stack = new Stack <MyClusterDescription>();
                List <MyClusterDescription>  list  = new List <MyClusterDescription>();
                MyClusterDescription         item  = new MyClusterDescription {
                    AABB           = bbox,
                    DynamicObjects = source.Where <MyObjectData>(delegate(MyObjectData x) {
                        if (x.ActivationHandler != null)
                        {
                            return(!x.ActivationHandler.IsStaticForCluster);
                        }
                        return(true);
                    }).ToList <MyObjectData>(),
                    StaticObjects = (from x in source
                                     where (x.ActivationHandler != null) && x.ActivationHandler.IsStaticForCluster
                                     select x).ToList <MyObjectData>()
                };
                stack.Push(item);
                List <MyObjectData> list2 = (from x in item.StaticObjects
                                             where x.Cluster != null
                                             select x).ToList <MyObjectData>();
                int count = item.StaticObjects.Count;
                while (stack.Count > 0)
                {
                    MyClusterDescription description2 = stack.Pop();
                    if (description2.DynamicObjects.Count != 0)
                    {
                        BoundingBoxD xd2 = BoundingBoxD.CreateInvalid();
                        for (int i = 0; i < description2.DynamicObjects.Count; i++)
                        {
                            MyObjectData data2    = description2.DynamicObjects[i];
                            BoundingBoxD inflated = data2.AABB.GetInflated((Vector3)(IdealClusterSize / 2f));
                            xd2.Include(inflated);
                        }
                        BoundingBoxD xd4  = xd2;
                        Vector3D     max  = xd2.Max;
                        int          num5 = xd2.Size.AbsMaxComponent();
                        switch (num5)
                        {
                        case 0:
                            description2.DynamicObjects.Sort(AABBComparerX.Static);
                            break;

                        case 1:
                            description2.DynamicObjects.Sort(AABBComparerY.Static);
                            break;

                        case 2:
                            description2.DynamicObjects.Sort(AABBComparerZ.Static);
                            break;
                        }
                        bool flag2 = false;
                        if (xd2.Size.AbsMax() >= MaximumForSplit.AbsMax())
                        {
                            for (int j = 1; j < description2.DynamicObjects.Count; j++)
                            {
                                MyObjectData data3 = description2.DynamicObjects[j - 1];
                                MyObjectData data4 = description2.DynamicObjects[j];
                                BoundingBoxD xd5   = data3.AABB.GetInflated((Vector3)(IdealClusterSize / 2f));
                                if ((data4.AABB.GetInflated((Vector3)(IdealClusterSize / 2f)).Min.GetDim(num5) - xd5.Max.GetDim(num5)) > 0.0)
                                {
                                    flag2 = true;
                                    max.SetDim(num5, xd5.Max.GetDim(num5));
                                    break;
                                }
                            }
                        }
                        xd4.Max = max;
                        xd4.InflateToMinimum(IdealClusterSize);
                        MyClusterDescription description3 = new MyClusterDescription {
                            AABB           = xd4,
                            DynamicObjects = new List <MyObjectData>(),
                            StaticObjects  = new List <MyObjectData>()
                        };
                        foreach (MyObjectData data5 in description2.DynamicObjects.ToList <MyObjectData>())
                        {
                            if (xd4.Contains(data5.AABB) == ContainmentType.Contains)
                            {
                                description3.DynamicObjects.Add(data5);
                                description2.DynamicObjects.Remove(data5);
                            }
                        }
                        foreach (MyObjectData data6 in description2.StaticObjects.ToList <MyObjectData>())
                        {
                            switch (xd4.Contains(data6.AABB))
                            {
                            case ContainmentType.Contains:
                            case ContainmentType.Intersects:
                                description3.StaticObjects.Add(data6);
                                description2.StaticObjects.Remove(data6);
                                break;
                            }
                        }
                        description3.AABB = xd4;
                        if (description2.DynamicObjects.Count > 0)
                        {
                            BoundingBoxD xd7 = BoundingBoxD.CreateInvalid();
                            foreach (MyObjectData data7 in description2.DynamicObjects)
                            {
                                xd7.Include(data7.AABB.GetInflated(MinimumDistanceFromBorder));
                            }
                            xd7.InflateToMinimum(IdealClusterSize);
                            MyClusterDescription description4 = new MyClusterDescription {
                                AABB           = xd7,
                                DynamicObjects = description2.DynamicObjects.ToList <MyObjectData>(),
                                StaticObjects  = description2.StaticObjects.ToList <MyObjectData>()
                            };
                            if (description4.AABB.Size.AbsMax() > (2f * IdealClusterSize.AbsMax()))
                            {
                                stack.Push(description4);
                            }
                            else
                            {
                                list.Add(description4);
                            }
                        }
                        if ((description3.AABB.Size.AbsMax() > (2f * IdealClusterSize.AbsMax())) && flag2)
                        {
                            stack.Push(description3);
                        }
                        else
                        {
                            list.Add(description3);
                        }
                    }
                }
                HashSet <MyCluster> set2 = new HashSet <MyCluster>();
                HashSet <MyCluster> set3 = new HashSet <MyCluster>();
                foreach (MyObjectData data8 in list2)
                {
                    if (data8.Cluster != null)
                    {
                        set2.Add(data8.Cluster);
                        this.RemoveObjectFromCluster(data8, true);
                    }
                }
                foreach (MyObjectData data9 in list2)
                {
                    if (data9.Cluster != null)
                    {
                        data9.ActivationHandler.FinishRemoveBatch(data9.Cluster.UserData);
                        data9.Cluster = null;
                    }
                }
                int num7 = 0;
                foreach (MyClusterDescription description7 in list)
                {
                    BoundingBoxD aABB    = description7.AABB;
                    MyCluster    cluster = this.CreateCluster(ref aABB);
                    foreach (MyObjectData data10 in description7.DynamicObjects)
                    {
                        if (data10.Cluster != null)
                        {
                            set2.Add(data10.Cluster);
                            this.RemoveObjectFromCluster(data10, true);
                        }
                    }
                    foreach (MyObjectData data11 in description7.DynamicObjects)
                    {
                        if (data11.Cluster != null)
                        {
                            data11.ActivationHandler.FinishRemoveBatch(data11.Cluster.UserData);
                            data11.Cluster = null;
                        }
                    }
                    foreach (MyCluster cluster2 in set2)
                    {
                        if (this.OnFinishBatch != null)
                        {
                            this.OnFinishBatch(cluster2.UserData);
                        }
                    }
                    foreach (MyObjectData data12 in description7.DynamicObjects)
                    {
                        this.AddObjectToCluster(cluster, data12.Id, true);
                    }
                    foreach (MyObjectData data13 in description7.StaticObjects)
                    {
                        if (cluster.AABB.Contains(data13.AABB) != ContainmentType.Disjoint)
                        {
                            this.AddObjectToCluster(cluster, data13.Id, true);
                            num7++;
                        }
                    }
                    set3.Add(cluster);
                }
                foreach (MyCluster cluster3 in set2)
                {
                    this.RemoveCluster(cluster3);
                }
                foreach (MyCluster cluster4 in set3)
                {
                    if (this.OnFinishBatch != null)
                    {
                        this.OnFinishBatch(cluster4.UserData);
                    }
                    foreach (ulong num8 in cluster4.Objects)
                    {
                        if (this.m_objectsData[num8].ActivationHandler != null)
                        {
                            this.m_objectsData[num8].ActivationHandler.FinishAddBatch();
                        }
                    }
                }
                if (this.OnClustersReordered != null)
                {
                    this.OnClustersReordered();
                }
            }
        }
        public void MoveObject(ulong id, BoundingBoxD oldAabb, BoundingBoxD aabb, Vector3 velocity)
        {
            System.Diagnostics.Debug.Assert(id != CLUSTERED_OBJECT_ID_UNITIALIZED, "Unitialized object in cluster!");

            MyObjectData objectData;

            if (m_objectsData.TryGetValue(id, out objectData))
            {
                System.Diagnostics.Debug.Assert(!objectData.ActivationHandler.IsStaticForCluster, "Cannot move static object!");

                var oldAABB = objectData.AABB;
                m_objectsData[id].AABB = aabb;

                BoundingBoxD originalAABB = aabb;
                Vector3      velocityDir  = velocity;

                if (velocity.LengthSquared() > 0.001f)
                {
                    velocityDir = Vector3.Normalize(velocity);
                }

                BoundingBoxD extendedAABB = aabb.Include(aabb.Center + velocityDir * 2000);
                //                BoundingBoxD newClusterAABB = aabb.Include(aabb.Center + velocityDir * IdealClusterSize / 2);

                originalAABB.InflateToMinimum(IdealClusterSize);

                System.Diagnostics.Debug.Assert(m_clusters.Contains(objectData.Cluster));

                var newContainmentType = objectData.Cluster.AABB.Contains(extendedAABB);
                if (newContainmentType != ContainmentType.Contains && !SingleCluster.HasValue)
                {
                    if (newContainmentType == ContainmentType.Disjoint)
                    { //Probably caused by teleport
                        m_clusterTree.OverlapAllBoundingBox(ref extendedAABB, m_returnedClusters);
                        if ((m_returnedClusters.Count == 1) && (m_returnedClusters[0].AABB.Contains(extendedAABB) == ContainmentType.Contains))
                        { //Just move object from one cluster to another
                            var oldCluster = objectData.Cluster;
                            RemoveObjectFromCluster(objectData, false);
                            if (oldCluster.Objects.Count == 0)
                            {
                                RemoveCluster(oldCluster);
                            }

                            AddObjectToCluster(m_returnedClusters[0], objectData.Id, false);
                        }
                        else
                        {
                            ReorderClusters(originalAABB.Include(oldAABB), id);
                        }
                    }
                    else
                    {
                        ReorderClusters(originalAABB.Include(oldAABB), id);
                    }
                }

                System.Diagnostics.Debug.Assert(m_objectsData[id].Cluster.AABB.Contains(objectData.AABB) == ContainmentType.Contains || SingleCluster.HasValue, "Inconsistency in clusters");
            }

            //foreach (var ob in m_objectsData)
            //{
            //    if (ob.Value.ActivationHandler.IsStatic && ob.Value.Cluster != null)
            //        System.Diagnostics.Debug.Assert(ob.Value.Cluster.AABB.Contains(ob.Value.AABB) != ContainmentType.Disjoint, "Inconsistency in clusters");
            //    else
            //      if (!ob.Value.ActivationHandler.IsStatic)
            //        System.Diagnostics.Debug.Assert(ob.Value.Cluster.AABB.Contains(ob.Value.AABB) == ContainmentType.Contains, "Inconsistency in clusters");
            //}
        }