ulong AddObjectToCluster(MyCluster cluster, ulong objectId, bool batch) { System.Diagnostics.Debug.Assert(cluster.AABB.Contains(m_objectsData[objectId].AABB) != ContainmentType.Disjoint, "Adding object which is completely out"); cluster.Objects.Add(objectId); var objectData = m_objectsData[objectId]; m_objectsData[objectId].Id = objectId; m_objectsData[objectId].Cluster = cluster; if (batch) { if (objectData.ActivationHandler != null) { objectData.ActivationHandler.ActivateBatch(cluster.UserData, objectId); } } else { if (objectData.ActivationHandler != null) { objectData.ActivationHandler.Activate(cluster.UserData, objectId); } } return(objectId); }
public void RemoveObject(ulong id) { System.Diagnostics.Debug.Assert(id != CLUSTERED_OBJECT_ID_UNITIALIZED, "Unitialized object in cluster!"); MyObjectData objectData; if (m_objectsData.TryGetValue(id, out objectData)) { MyCluster cluster = objectData.Cluster; if (cluster != null) { RemoveObjectFromCluster(objectData, false); if (cluster.Objects.Count == 0) { RemoveCluster(cluster); } } if (objectData.StaticId != MyDynamicAABBTreeD.NullNode) { m_staticTree.RemoveProxy(objectData.StaticId); objectData.StaticId = MyDynamicAABBTreeD.NullNode; } m_objectsData.Remove(id); } else { System.Diagnostics.Debug.Fail("Removed object is not in cluster"); } }
private void RemoveCluster(MyCluster cluster) { this.m_clusterTree.RemoveProxy(cluster.ClusterId); this.m_clusters.Remove(cluster); this.m_userObjects.Remove(cluster.UserData); if (this.OnClusterRemoved != null) { this.OnClusterRemoved(cluster.UserData); } }
private MyCluster CreateCluster(ref BoundingBoxD clusterBB) { MyCluster userData = new MyCluster { AABB = clusterBB, Objects = new HashSet <ulong>() }; userData.ClusterId = this.m_clusterTree.AddProxy(ref userData.AABB, userData, 0, true); if (this.OnClusterCreated != null) { userData.UserData = this.OnClusterCreated(userData.ClusterId, userData.AABB); } this.m_clusters.Add(userData); this.m_userObjects.Add(userData.UserData); return(userData); }
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); } } } } } }
private MyCluster CreateCluster(ref BoundingBoxD clusterBB) { MyCluster cluster = new MyCluster() //Center = {X:-10968.2552425968 Y:-3958.99401506744 Z:-188.682065703847} Max = {X:11118.0759795131 Y:11202.10024965 Z:11287.440539642}Min = {X:-33054.5864647067 Y:-19120.0882797849 Z:-11664.8046710497} { AABB = clusterBB, Objects = new HashSet <ulong>() }; cluster.ClusterId = m_clusterTree.AddProxy(ref cluster.AABB, cluster, 0); if (OnClusterCreated != null) { cluster.UserData = OnClusterCreated(cluster.ClusterId, cluster.AABB); } m_clusters.Add(cluster); m_userObjects.Add(cluster.UserData); return(cluster); }
private MyCluster CreateCluster(ref BoundingBoxD clusterBB) { MyCluster cluster = new MyCluster() { AABB = clusterBB, Objects = new HashSet <ulong>() }; cluster.ClusterId = m_clusterTree.AddProxy(ref cluster.AABB, cluster, 0); if (OnClusterCreated != null) { cluster.UserData = OnClusterCreated(cluster.ClusterId, cluster.AABB); } m_clusters.Add(cluster); m_userObjects.Add(cluster.UserData); return(cluster); }
private ulong AddObjectToCluster(MyCluster cluster, ulong objectId, bool batch) { cluster.Objects.Add(objectId); MyObjectData data = this.m_objectsData[objectId]; this.m_objectsData[objectId].Id = objectId; this.m_objectsData[objectId].Cluster = cluster; if (batch) { if (data.ActivationHandler != null) { data.ActivationHandler.ActivateBatch(cluster.UserData, objectId); } return(objectId); } if (data.ActivationHandler != null) { data.ActivationHandler.Activate(cluster.UserData, objectId); } return(objectId); }
public void RemoveObject(ulong id) { MyObjectData data; if (this.m_objectsData.TryGetValue(id, out data)) { MyCluster cluster = data.Cluster; if (cluster != null) { this.RemoveObjectFromCluster(data, false); if (cluster.Objects.Count == 0) { this.RemoveCluster(cluster); } } if (data.StaticId != -1) { this.m_staticTree.RemoveProxy(data.StaticId); data.StaticId = -1; } this.m_objectsData.Remove(id); } }
public MyStack() { var myConfig = new MyConfig(); var myCluster = new MyCluster(myConfig); var chart = new Chart("apache-chart", new ChartArgs { Chart = "apache", Version = "8.3.2", FetchOptions = new ChartFetchArgs { Repo = "https://charts.bitnami.com/bitnami" } }, new ComponentResourceOptions { Provider = myCluster.Provider }); this.ApacheServiceIP = chart.GetResource <Service>("apache-chart") .Apply(svc => svc.Status.Apply(s => s.LoadBalancer.Ingress[0].Ip)); this.ClusterName = myCluster.ClusterName; this.Kubeconfig = myCluster.Kubeconfig; }
//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 ulong AddObject(BoundingBoxD bbox, Vector3 velocity, IMyActivationHandler activationHandler, ulong?customId) { if (SingleCluster.HasValue && m_clusters.Count == 0) { BoundingBoxD bb = SingleCluster.Value; bb.Inflate(200); //inflate 200m so objects near world border have AABB inside => physics created CreateCluster(ref bb); } BoundingBoxD inflatedBBox; if (SingleCluster.HasValue) { inflatedBBox = bbox; } else { inflatedBBox = bbox.GetInflated(MinimumDistanceFromBorder); } m_clusterTree.OverlapAllBoundingBox(ref inflatedBBox, m_returnedClusters); MyCluster cluster = null; bool needReorder = false; if (m_returnedClusters.Count == 1) { if (m_returnedClusters[0].AABB.Contains(inflatedBBox) == ContainmentType.Contains) { cluster = m_returnedClusters[0]; } else if (m_returnedClusters[0].AABB.Contains(inflatedBBox) == ContainmentType.Intersects && activationHandler.IsStaticForCluster) { if (m_returnedClusters[0].AABB.Contains(bbox) == ContainmentType.Disjoint) { //completely out } else { cluster = m_returnedClusters[0]; } } else { needReorder = true; } } else if (m_returnedClusters.Count > 1) { needReorder = true; } else if (m_returnedClusters.Count == 0) { if (!activationHandler.IsStaticForCluster) { var clusterBB = new BoundingBoxD(bbox.Center - IdealClusterSize / 2, bbox.Center + IdealClusterSize / 2); m_clusterTree.OverlapAllBoundingBox(ref clusterBB, m_returnedClusters); if (m_returnedClusters.Count == 0) { //Space is empty, create new cluster m_staticTree.OverlapAllBoundingBox(ref clusterBB, m_objectDataResultList); cluster = CreateCluster(ref clusterBB); foreach (var ob in m_objectDataResultList) { System.Diagnostics.Debug.Assert(m_objectsData[ob].Cluster == null, "Found object must not be in cluster!"); AddObjectToCluster(cluster, ob, false); } } else //There is still some blocking cluster { needReorder = true; } } } ulong objectId = customId.HasValue ? customId.Value : m_clusterObjectCounter++; int staticObjectId = MyDynamicAABBTreeD.NullNode; m_objectsData[objectId] = new MyObjectData() { Id = objectId, Cluster = cluster, ActivationHandler = activationHandler, AABB = bbox, StaticId = staticObjectId }; System.Diagnostics.Debug.Assert(!needReorder || (!SingleCluster.HasValue && needReorder), "Object cannot be added outside borders of a single cluster"); if (needReorder && !SingleCluster.HasValue) { System.Diagnostics.Debug.Assert(cluster == null, "Error in cluster logic"); ReorderClusters(bbox, objectId); if (!m_objectsData[objectId].ActivationHandler.IsStaticForCluster) { System.Diagnostics.Debug.Assert(m_objectsData[objectId].Cluster != null, "Object not added"); } #if DEBUG m_clusterTree.OverlapAllBoundingBox(ref bbox, m_returnedClusters); System.Diagnostics.Debug.Assert(m_returnedClusters.Count <= 1, "Clusters overlap!"); if (m_returnedClusters.Count != 0) { System.Diagnostics.Debug.Assert(activationHandler.IsStaticForCluster ? m_returnedClusters[0].AABB.Contains(inflatedBBox) != ContainmentType.Disjoint : m_returnedClusters[0].AABB.Contains(inflatedBBox) == ContainmentType.Contains, "Clusters reorder failure!"); } #endif } if (activationHandler.IsStaticForCluster) { staticObjectId = m_staticTree.AddProxy(ref bbox, objectId, 0); m_objectsData[objectId].StaticId = staticObjectId; } if (cluster != null) { return(AddObjectToCluster(cluster, objectId, false)); } else { return(objectId); } }
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 ulong AddObject(BoundingBoxD bbox, IMyActivationHandler activationHandler, ulong?customId, string tag, long entityId, bool batch) { using (this.m_clustersLock.AcquireExclusiveUsing()) { BoundingBoxD inflated; ulong num5; if (this.SingleCluster.HasValue && (this.m_clusters.Count == 0)) { BoundingBoxD clusterBB = this.SingleCluster.Value; clusterBB.Inflate((double)200.0); this.CreateCluster(ref clusterBB); } if (this.SingleCluster.HasValue || this.ForcedClusters) { inflated = bbox; } else { inflated = bbox.GetInflated(MinimumDistanceFromBorder); } this.m_clusterTree.OverlapAllBoundingBox <MyCluster>(ref inflated, this.m_returnedClusters, 0, true); MyCluster cluster = null; bool flag = false; if (this.m_returnedClusters.Count == 1) { if (this.m_returnedClusters[0].AABB.Contains(inflated) == ContainmentType.Contains) { cluster = this.m_returnedClusters[0]; } else if ((this.m_returnedClusters[0].AABB.Contains(inflated) == ContainmentType.Intersects) && activationHandler.IsStaticForCluster) { if (this.m_returnedClusters[0].AABB.Contains(bbox) != ContainmentType.Disjoint) { cluster = this.m_returnedClusters[0]; } } else { flag = true; } } else if (this.m_returnedClusters.Count > 1) { if (!activationHandler.IsStaticForCluster) { flag = true; } } else if (this.m_returnedClusters.Count == 0) { if (this.SingleCluster.HasValue) { return(ulong.MaxValue); } if (!activationHandler.IsStaticForCluster) { BoundingBoxD xd3 = new BoundingBoxD(bbox.Center - ((Vector3D)(IdealClusterSize / 2f)), bbox.Center + ((Vector3D)(IdealClusterSize / 2f))); this.m_clusterTree.OverlapAllBoundingBox <MyCluster>(ref xd3, this.m_returnedClusters, 0, true); if (this.m_returnedClusters.Count == 0) { this.m_staticTree.OverlapAllBoundingBox <ulong>(ref xd3, m_objectDataResultList, 0, true); cluster = this.CreateCluster(ref xd3); foreach (ulong num in m_objectDataResultList) { if (this.m_objectsData[num].Cluster == null) { this.AddObjectToCluster(cluster, num, false); } } } else { flag = true; } } } ulong objectId = customId.HasValue ? customId.Value : num5; int num3 = -1; MyObjectData data = new MyObjectData { Id = objectId, Cluster = cluster, ActivationHandler = activationHandler, AABB = bbox, StaticId = num3, Tag = tag, EntityId = entityId }; this.m_objectsData[objectId] = data; if ((flag && !this.SingleCluster.HasValue) && !this.ForcedClusters) { this.ReorderClusters(bbox, objectId); bool isStaticForCluster = this.m_objectsData[objectId].ActivationHandler.IsStaticForCluster; } if (activationHandler.IsStaticForCluster) { num3 = this.m_staticTree.AddProxy(ref bbox, objectId, 0, true); this.m_objectsData[objectId].StaticId = num3; } if (cluster != null) { return(this.AddObjectToCluster(cluster, objectId, batch)); } return(objectId); } }