private void FindForestInitialCandidate() { BoundingBoxD groundBox = m_ground.PositionComp.WorldAABB; Vector3D boxSize = groundBox.Size; boxSize *= 0.1f; groundBox.Inflate(-boxSize); MyBBSetSampler sampler = new MyBBSetSampler(groundBox.Min, groundBox.Max); bool posIsValid = true; Vector3D worldPos = default(Vector3D); int counter = 0; do { // find random position for starting worldPos = sampler.Sample(); var worldPosProjected = worldPos; worldPosProjected.Y = 0.5f; posIsValid = true; counter++; Vector3D areaCheck = new Vector3D(20, 20, 20); foreach (var enqueued in m_initialForestLocations) { // only interested in XZ plane BoundingBoxD tmp = new BoundingBoxD(enqueued - areaCheck, enqueued + areaCheck); tmp.Min.Y = 0; tmp.Max.Y = 1; if (tmp.Contains(worldPosProjected) == ContainmentType.Contains) { posIsValid = false; break; } } } while (!posIsValid && counter != 10); if (!posIsValid) { // could not find any position return; } var lineStart = new Vector3D(worldPos.X, groundBox.Max.Y, worldPos.Z); var lineEnd = new Vector3D(worldPos.X, groundBox.Min.Y, worldPos.Z); LineD line = new LineD(lineStart, lineEnd); VRage.Game.Models.MyIntersectionResultLineTriangleEx? result = null; var correctGroundDefinition = MyDefinitionManager.Static.GetVoxelMaterialDefinition("Grass"); var materialId = correctGroundDefinition.Index; if (m_ground.GetIntersectionWithLine(ref line, out result, VRage.Game.Components.IntersectionFlags.DIRECT_TRIANGLES)) { Vector3D intersectionPoint = result.Value.IntersectionPointInWorldSpace; Vector3I voxelCoord, minRead, maxRead; MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_ground.PositionLeftBottomCorner, ref intersectionPoint, out voxelCoord); minRead = voxelCoord - Vector3I.One; maxRead = voxelCoord + Vector3I.One; m_ground.Storage.ReadRange(m_voxelCache, MyStorageDataTypeFlags.Material, 0, ref minRead, ref maxRead); var minLocal = Vector3I.Zero; var maxLocal = Vector3I.One * 2; var it = new Vector3I_RangeIterator(ref minLocal, ref maxLocal); while (it.IsValid()) { var vec = it.Current; var material = m_voxelCache.Material(ref vec); if (material == materialId) { // found a location var desired = voxelCoord - Vector3I.One + vec; Vector3D desiredWorldPosition = default(Vector3D); MyVoxelCoordSystems.VoxelCoordToWorldPosition(m_ground.PositionLeftBottomCorner, ref desired, out desiredWorldPosition); m_initialForestLocations.Enqueue(desiredWorldPosition); break; } it.MoveNext(); } } }
public bool PointsInsideGizmo(List<Vector3> points, MyGizmoSpaceEnum gizmo, ref MatrixD invGridWorldMatrix, float gridSize, float inflate = 0.0f, bool onVoxel = false) { MatrixD m = new MatrixD(); BoundingBoxD gizmoBox = new BoundingBoxD(); GetGizmoPointTestVariables(ref invGridWorldMatrix, gridSize, out gizmoBox, out m, gizmo, inflate: inflate, onVoxel: onVoxel); foreach (var point in points) { Vector3 localPoint = Vector3.Transform(point, m); if (gizmoBox.Contains(localPoint) == ContainmentType.Contains) return true; } return false; }
//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(); } } }
/// <summary> /// Performes a physics raycast /// It can be recursive (it calls CastDDA when it hits a grid). /// </summary> /// <param name="fromWorldPos"></param> /// <returns>Returns starting damage for current stack</returns> private MyRaycastDamageInfo CastPhysicsRay(Vector3D fromWorldPos) { Vector3D pos = Vector3D.Zero; IMyEntity hitEntity = null; var hitInfo = MyPhysics.CastRay(fromWorldPos, m_explosion.Center, MyPhysics.ExplosionRaycastLayer); if (hitInfo.HasValue) { hitEntity = (hitInfo.Value.HkHitInfo.Body.UserObject != null) ? ((MyPhysicsBody)hitInfo.Value.HkHitInfo.Body.UserObject).Entity : null; pos = hitInfo.Value.Position; } Vector3D direction = (m_explosion.Center - fromWorldPos); float lengthToCenter = (float)direction.Length(); direction.Normalize(); var grid = (hitEntity as MyCubeGrid); if (grid == null) { MyCubeBlock hitBlock = hitEntity as MyCubeBlock; if (hitBlock != null) { grid = hitBlock.CubeGrid; } } if (grid != null) { //Try advancing the point to find the intersected block //If the block is a cube, this is necessary because the raycast will return a point somewhere outside the cube //If the block is not a full cube (slope, special block), the raycast can return inside the cube //It advances 4 times, each time one 8th the grid size for (int i = 0; i < 5; i++) { Vector3D localPos = Vector3D.Transform(pos, grid.PositionComp.WorldMatrixNormalizedInv) / grid.GridSize; Vector3I gridPos = Vector3I.Round(localPos); var cubeBlock = grid.GetCubeBlock(gridPos); if (cubeBlock != null) { if (m_castBlocks.Contains(cubeBlock)) { //This shouldn't happen //There is a corner case where the explosion position is inside the empty cell, but this should be handleded somewhere higher System.Diagnostics.Debug.Fail("Raycast failed!"); DrawRay(fromWorldPos, pos, Color.Red); return new MyRaycastDamageInfo(0f, lengthToCenter); } else { if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) DrawRay(fromWorldPos, pos, Color.Blue); return CastDDA(cubeBlock); } } pos += direction * grid.GridSize / 8f; } //We hit a grid but were unable to find the hit cube. Send another raycast //Ideally, we would want to get the cube in all cases, but it also has to be fast //We need to check if the explosion center is between the initial start position (fromWorldPos) and the new one (pos) Vector3D min = new Vector3D(Math.Min(fromWorldPos.X, pos.X), Math.Min(fromWorldPos.Y, pos.Y), Math.Min(fromWorldPos.Z, pos.Z)); Vector3D max = new Vector3D(Math.Max(fromWorldPos.X, pos.X), Math.Max(fromWorldPos.Y, pos.Y), Math.Max(fromWorldPos.Z, pos.Z)); BoundingBoxD boundingBox = new BoundingBoxD(min, max); if (boundingBox.Contains(m_explosion.Center) == ContainmentType.Contains) { return new MyRaycastDamageInfo(m_explosionDamage, lengthToCenter); } stackOverflowGuard++; if (stackOverflowGuard > MAX_PHYSICS_RECURSION_COUNT) { System.Diagnostics.Debug.Fail("Potential stack overflow!"); if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) DrawRay(fromWorldPos, pos, Color.Red); return new MyRaycastDamageInfo(0f, lengthToCenter); } else { if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) DrawRay(fromWorldPos, pos, Color.White); return CastPhysicsRay(pos); } } else if (hitInfo.HasValue) { //Something was hit, but it wasn't a grid. This needs to be handled somehow if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) DrawRay(fromWorldPos, pos, Color.Violet); return new MyRaycastDamageInfo(0, lengthToCenter); } //Nothing was hit, so we can assume the there was nothing blocking the explosion if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) DrawRay(fromWorldPos, pos, Color.Salmon); return new MyRaycastDamageInfo(m_explosionDamage, lengthToCenter); }
private new bool TestPlacement() { bool retval = true; m_touchingGrids.Clear(); for (int i = 0; i < PreviewGrids.Count; ++i) { var grid = PreviewGrids[i]; m_touchingGrids.Add(null); if (MyCubeBuilder.Static.DynamicMode) { if (!m_dynamicBuildAllowed) { var settings = m_settings.GetGridPlacementSettings(grid, false); BoundingBoxD localAabb = (BoundingBoxD)grid.PositionComp.LocalAABB; MatrixD worldMatrix = grid.WorldMatrix; if (MyFakes.ENABLE_VOXEL_MAP_AABB_CORNER_TEST) { retval = retval && MyCubeGrid.TestPlacementVoxelMapOverlap(null, ref settings, ref localAabb, ref worldMatrix); } retval = retval && MyCubeGrid.TestPlacementArea(grid, false, ref settings, localAabb, true); if (!retval) { break; } //foreach (var block in grid.GetBlocks()) //{ // Vector3 minLocal = block.Min * PreviewGrids[i].GridSize - Vector3.Half * PreviewGrids[i].GridSize; // Vector3 maxLocal = block.Max * PreviewGrids[i].GridSize + Vector3.Half * PreviewGrids[i].GridSize; // BoundingBoxD aabbLocal = new BoundingBoxD(minLocal, maxLocal); // retval &= MyCubeGrid.TestPlacementArea(grid, false, ref settings, aabbLocal, true); // if (!retval) // break; //} } } else { //not dynamic building mode if (i == 0 && m_hitEntity is MyCubeGrid && IsSnapped && SnapMode == MyGridPlacementSettings.SnapMode.Base6Directions) { var settings = grid.GridSizeEnum == MyCubeSize.Large ? MyPerGameSettings.BuildingSettings.LargeStaticGrid : MyPerGameSettings.BuildingSettings.SmallStaticGrid; var hitGrid = m_hitEntity as MyCubeGrid; if (hitGrid.GridSizeEnum == MyCubeSize.Small && grid.GridSizeEnum == MyCubeSize.Large) { retval = false; break; } bool smallOnLargeGrid = hitGrid.GridSizeEnum == MyCubeSize.Large && grid.GridSizeEnum == MyCubeSize.Small; if (MyFakes.ENABLE_STATIC_SMALL_GRID_ON_LARGE /*&& grid.IsStatic*/ && smallOnLargeGrid) { if (!hitGrid.IsStatic) { retval = false; break; } foreach (var block in grid.CubeBlocks) { if (block.FatBlock is MyCompoundCubeBlock) { MyCompoundCubeBlock compoundBlock = block.FatBlock as MyCompoundCubeBlock; foreach (var blockInCompound in compoundBlock.GetBlocks()) { retval = retval && TestBlockPlacement(blockInCompound, ref settings); if (!retval) { break; } } } else { retval = retval && TestBlockPlacement(block, ref settings); } if (!retval) { break; } } } else { retval = retval && TestGridPlacementOnGrid(grid, ref settings, hitGrid); } } else { // Check with grid settings { MyCubeGrid touchingGrid = null; var settings = i == 0 ? (grid.GridSizeEnum == MyCubeSize.Large ? MyPerGameSettings.BuildingSettings.LargeStaticGrid : MyPerGameSettings.BuildingSettings.SmallStaticGrid) : MyPerGameSettings.BuildingSettings.GetGridPlacementSettings(grid); if (grid.IsStatic) { if (i == 0) { Matrix orientation = grid.WorldMatrix.GetOrientation(); retval = retval && MyCubeBuilder.CheckValidBlocksRotation(orientation, grid); } foreach (var block in grid.CubeBlocks) { if (block.FatBlock is MyCompoundCubeBlock) { MyCompoundCubeBlock compoundBlock = block.FatBlock as MyCompoundCubeBlock; foreach (var blockInCompound in compoundBlock.GetBlocks()) { MyCubeGrid touchingGridLocal = null; retval = retval && TestBlockPlacementNoAABBInflate(blockInCompound, ref settings, out touchingGridLocal); if (retval && touchingGridLocal != null && touchingGrid == null) { touchingGrid = touchingGridLocal; } if (!retval) { break; } } } else { MyCubeGrid touchingGridLocal = null; retval = retval && TestBlockPlacementNoAABBInflate(block, ref settings, out touchingGridLocal); if (retval && touchingGridLocal != null && touchingGrid == null) { touchingGrid = touchingGridLocal; } } if (!retval) { break; } } if (retval && touchingGrid != null) { m_touchingGrids[i] = touchingGrid; } } else { foreach (var block in grid.CubeBlocks) { Vector3 minLocal = block.Min * PreviewGrids[i].GridSize - Vector3.Half * PreviewGrids[i].GridSize; Vector3 maxLocal = block.Max * PreviewGrids[i].GridSize + Vector3.Half * PreviewGrids[i].GridSize; BoundingBoxD aabbLocal = new BoundingBoxD(minLocal, maxLocal); retval = retval && MyCubeGrid.TestPlacementArea(grid, grid.IsStatic, ref settings, aabbLocal, false); if (!retval) { break; } } m_touchingGrids[i] = null; } } // Check connectivity with touching grid if (retval && m_touchingGrids[i] != null) { var settings = grid.GridSizeEnum == MyCubeSize.Large ? MyPerGameSettings.BuildingSettings.LargeStaticGrid : MyPerGameSettings.BuildingSettings.SmallStaticGrid; retval = retval && TestGridPlacementOnGrid(grid, ref settings, m_touchingGrids[i]); } // Check with paste settings only first grid { if (retval && i == 0) { bool smallStaticGrid = grid.GridSizeEnum == MyCubeSize.Small && grid.IsStatic; if (smallStaticGrid || !grid.IsStatic) { var settings = i == 0 ? m_settings.GetGridPlacementSettings(grid, false) : MyPerGameSettings.BuildingSettings.SmallStaticGrid; bool localRetVal = true; foreach (var block in grid.CubeBlocks) { Vector3 minLocal = block.Min * PreviewGrids[i].GridSize - Vector3.Half * PreviewGrids[i].GridSize; Vector3 maxLocal = block.Max * PreviewGrids[i].GridSize + Vector3.Half * PreviewGrids[i].GridSize; BoundingBoxD blockLocalAABB = new BoundingBoxD(minLocal, maxLocal); localRetVal = localRetVal && MyCubeGrid.TestPlacementArea(grid, false, ref settings, blockLocalAABB, false); if (!localRetVal) { break; } } retval &= !localRetVal; } else if (m_touchingGrids[i] == null) { var settings = m_settings.GetGridPlacementSettings(grid, i == 0 ? true : grid.IsStatic); MyCubeGrid touchingGridLocal = null; bool localRetVal = false; foreach (var block in grid.CubeBlocks) { if (block.FatBlock is MyCompoundCubeBlock) { MyCompoundCubeBlock compoundBlock = block.FatBlock as MyCompoundCubeBlock; foreach (var blockInCompound in compoundBlock.GetBlocks()) { localRetVal |= TestBlockPlacementNoAABBInflate(blockInCompound, ref settings, out touchingGridLocal); if (localRetVal) { break; } } } else { localRetVal |= TestBlockPlacementNoAABBInflate(block, ref settings, out touchingGridLocal); } if (localRetVal) { break; } } retval &= localRetVal; } } } } } BoundingBoxD aabb = (BoundingBoxD)grid.PositionComp.LocalAABB; MatrixD invGridWorlMatrix = grid.PositionComp.WorldMatrixNormalizedInv; // Character collisions. if (MySector.MainCamera != null) { Vector3D cameraPos = Vector3D.Transform(MySector.MainCamera.Position, invGridWorlMatrix); retval = retval && aabb.Contains(cameraPos) != ContainmentType.Contains; } if (retval) { m_tmpCollisionPoints.Clear(); MyCubeBuilder.PrepareCharacterCollisionPoints(m_tmpCollisionPoints); foreach (var pt in m_tmpCollisionPoints) { Vector3D ptLocal = Vector3D.Transform(pt, invGridWorlMatrix); retval = retval && aabb.Contains(ptLocal) != ContainmentType.Contains; if (!retval) { break; } } } if (!retval) { break; } } return(retval); }
public bool PointsAABBIntersectsGizmo(List<Vector3D> points, MyGizmoSpaceEnum gizmo, ref MatrixD invGridWorldMatrix, float gridSize, float inflate = 0.0f, bool onVoxel = false, bool dynamicMode = false) { MatrixD m = new MatrixD(); BoundingBoxD gizmoBox = new BoundingBoxD(); GetGizmoPointTestVariables(ref invGridWorldMatrix, gridSize, out gizmoBox, out m, gizmo, inflate: inflate, onVoxel: onVoxel, dynamicMode: dynamicMode); BoundingBoxD pointsBox = BoundingBoxD.CreateInvalid(); foreach (var point in points) { Vector3D localPoint = Vector3D.Transform(point, m); if (gizmoBox.Contains(localPoint) == ContainmentType.Contains) return true; pointsBox.Include(localPoint); } return pointsBox.Intersects(ref gizmoBox); }
private Vector3D?FindSuitableJumpLocationSpace(Vector3D desiredLocation) { List <MyObjectSeed> m_objectsInRange = new List <MyObjectSeed>(); List <BoundingBoxD> m_obstaclesInRange = new List <BoundingBoxD>(); List <MyEntity> m_entitiesInRange = new List <MyEntity>(); BoundingSphereD Inflated = SphereD; Inflated.Radius *= 1.5; Inflated.Center = desiredLocation; Vector3D vector3D = desiredLocation; MyProceduralWorldGenerator.Static.OverlapAllAsteroidSeedsInSphere(Inflated, m_objectsInRange); foreach (MyObjectSeed item3 in m_objectsInRange) { m_obstaclesInRange.Add(item3.BoundingVolume); } m_objectsInRange.Clear(); MyProceduralWorldGenerator.Static.GetAllInSphere <MyStationCellGenerator>(Inflated, m_objectsInRange); foreach (MyObjectSeed item4 in m_objectsInRange) { MyStation myStation = item4.UserData as MyStation; if (myStation != null) { BoundingBoxD item = new BoundingBoxD(myStation.Position - MyStation.SAFEZONE_SIZE, myStation.Position + MyStation.SAFEZONE_SIZE); if (item.Contains(vector3D) != 0) { m_obstaclesInRange.Add(item); } } } m_objectsInRange.Clear(); MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref Inflated, m_entitiesInRange); foreach (MyEntity item5 in m_entitiesInRange) { if (!(item5 is MyPlanet)) { m_obstaclesInRange.Add(item5.PositionComp.WorldAABB.GetInflated(Inflated.Radius)); } } int num = 10; int num2 = 0; BoundingBoxD?boundingBoxD = null; bool flag = false; bool flag2 = false; while (num2 < num) { num2++; flag = false; foreach (BoundingBoxD item6 in m_obstaclesInRange) { ContainmentType containmentType = item6.Contains(vector3D); if (containmentType == ContainmentType.Contains || containmentType == ContainmentType.Intersects) { if (!boundingBoxD.HasValue) { boundingBoxD = item6; } boundingBoxD = boundingBoxD.Value.Include(item6); boundingBoxD = boundingBoxD.Value.Inflate(1.0); vector3D = ClosestPointOnBounds(boundingBoxD.Value, vector3D); flag = true; break; } } if (!flag) { flag2 = true; break; } } m_obstaclesInRange.Clear(); m_entitiesInRange.Clear(); m_objectsInRange.Clear(); if (flag2) { return(vector3D); } return(null); }
public bool ExtractStationIntersect(IMainView mainViewModel, bool tightIntersection) { // Make a shortlist of station Entities in the bounding box of the asteroid. var asteroidWorldAABB = new BoundingBoxD((Vector3D)ContentBounds.Min + PositionAndOrientation.Value.Position, (Vector3D)ContentBounds.Max + PositionAndOrientation.Value.Position); var stations = mainViewModel.GetIntersectingEntities(asteroidWorldAABB).Where(e => e.ClassType == ClassType.LargeStation).Cast <StructureCubeGridModel>().ToList(); if (stations.Count == 0) { return(false); } var modified = false; var sourceFile = SourceVoxelFilepath ?? VoxelFilepath; var asteroid = new MyVoxelMap(); asteroid.Load(sourceFile); var total = stations.Sum(s => s.CubeGrid.CubeBlocks.Count); mainViewModel.ResetProgress(0, total); // Search through station entities cubes for intersection with this voxel. foreach (var station in stations) { var quaternion = station.PositionAndOrientation.Value.ToQuaternion(); foreach (var cube in station.CubeGrid.CubeBlocks) { mainViewModel.IncrementProgress(); var definition = SpaceEngineersApi.GetCubeDefinition(cube.TypeId, station.CubeGrid.GridSizeEnum, cube.SubtypeName); var orientSize = definition.Size.Transform(cube.BlockOrientation).Abs(); var min = cube.Min.ToVector3() * station.CubeGrid.GridSizeEnum.ToLength(); var max = (cube.Min + orientSize) * station.CubeGrid.GridSizeEnum.ToLength(); var p1 = Vector3D.Transform(min, quaternion) + station.PositionAndOrientation.Value.Position - (station.CubeGrid.GridSizeEnum.ToLength() / 2); var p2 = Vector3D.Transform(max, quaternion) + station.PositionAndOrientation.Value.Position - (station.CubeGrid.GridSizeEnum.ToLength() / 2); var cubeWorldAABB = new BoundingBoxD(Vector3.Min(p1, p2), Vector3.Max(p1, p2)); // find worldAABB of block. if (asteroidWorldAABB.Intersects(cubeWorldAABB)) { Vector3I block; var cacheSize = new Vector3I(64); Vector3D position = PositionAndOrientation.Value.Position; // read the asteroid in chunks of 64 to avoid the Arithmetic overflow issue. for (block.Z = 0; block.Z < asteroid.Storage.Size.Z; block.Z += 64) { for (block.Y = 0; block.Y < asteroid.Storage.Size.Y; block.Y += 64) { for (block.X = 0; block.X < asteroid.Storage.Size.X; block.X += 64) { var cache = new MyStorageData(); cache.Resize(cacheSize); // LOD1 is not detailed enough for content information on asteroids. Vector3I maxRange = block + cacheSize - 1; asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.Content, 0, block, maxRange); bool changed = false; Vector3I p; for (p.Z = 0; p.Z < cacheSize.Z; ++p.Z) { for (p.Y = 0; p.Y < cacheSize.Y; ++p.Y) { for (p.X = 0; p.X < cacheSize.X; ++p.X) { BoundingBoxD voxelCellBox = new BoundingBoxD(position + p + block, position + p + block + 1); ContainmentType contains = cubeWorldAABB.Contains(voxelCellBox); // TODO: finish tightIntersection. Will require high interpretation of voxel content volumes. if (contains == ContainmentType.Contains || contains == ContainmentType.Intersects) { cache.Content(ref p, 0); changed = true; } } } } if (changed) { asteroid.Storage.WriteRange(cache, MyStorageDataTypeFlags.Content, block, maxRange); modified = true; } } } } } } } mainViewModel.ClearProgress(); if (modified) { var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension); asteroid.Save(tempfilename); // replaces the existing asteroid file, as it is still the same size and dimentions. UpdateNewSource(asteroid, tempfilename); MaterialAssets = null; InitializeAsync(); } return(modified); }
public static unsafe void DisableItemsInAabb(this MyEnvironmentSector sector, ref BoundingBoxD aabb) { if (sector.DataView == null) return; aabb.Translate(-sector.SectorCenter); for (int sectorInd = 0; sectorInd < sector.DataView.LogicalSectors.Count; sectorInd++) { var logicalSector = sector.DataView.LogicalSectors[sectorInd]; var logicalItems = logicalSector.Items; var cnt = logicalItems.Count; fixed (ItemInfo* items = logicalItems.GetInternalArray()) for (int i = 0; i < cnt; ++i) { if (items[i].DefinitionIndex >= 0 && aabb.Contains(items[i].Position) != ContainmentType.Disjoint) logicalSector.EnableItem(i, false); } } }
private new bool TestPlacement() { bool retval = true; m_touchingGrids.Clear(); for (int i = 0; i < PreviewGrids.Count; ++i) { var grid = PreviewGrids[i]; var settings = m_settings.GetGridPlacementSettings(grid.GridSizeEnum); m_touchingGrids.Add(null); if (MySession.Static.SurvivalMode && !MyCubeBuilder.SpectatorIsBuilding && !MySession.Static.IsAdminModeEnabled(Sync.MyId)) { if (i == 0 && MyCubeBuilder.CameraControllerSpectator) { m_visible = false; return(false); } if (i == 0 && !MyCubeBuilder.Static.DynamicMode) { MatrixD invMatrix = grid.PositionComp.WorldMatrixNormalizedInv; if (!MyCubeBuilderGizmo.DefaultGizmoCloseEnough(ref invMatrix, (BoundingBoxD)grid.PositionComp.LocalAABB, grid.GridSize, MyCubeBuilder.IntersectionDistance)) { m_visible = false; return(false); } } /*if (!MySession.Static.SimpleSurvival && MySession.Static.ControlledEntity is MyCharacter) * { * foreach (var block in grid.GetBlocks()) * { * retval &= (MySession.Static.ControlledEntity as MyCharacter).CanStartConstruction(block.BlockDefinition); * if (!retval) * break; * } * } * * if (i == 0 && MySession.Static.SimpleSurvival) * { * retval = retval && MyCubeBuilder.Static.CanBuildBlockSurvivalTime(); * }*/ if (!retval) { return(false); } } if (MyCubeBuilder.Static.DynamicMode) { // if (!m_dynamicBuildAllowed) // { var settingsLocal = grid.GridSizeEnum == MyCubeSize.Large ? m_settings.LargeGrid : m_settings.SmallGrid; bool anyBlockVoxelHit = false; foreach (var block in grid.GetBlocks()) { Vector3 minLocal = block.Min * PreviewGrids[i].GridSize - Vector3.Half * PreviewGrids[i].GridSize; Vector3 maxLocal = block.Max * PreviewGrids[i].GridSize + Vector3.Half * PreviewGrids[i].GridSize; BoundingBoxD aabbLocal = new BoundingBoxD(minLocal, maxLocal); if (!anyBlockVoxelHit) { anyBlockVoxelHit = TestVoxelPlacement(block, ref settings, true); } retval = retval && MyCubeGrid.TestPlacementArea(grid, grid.IsStatic, ref settingsLocal, aabbLocal, true, testVoxel: false); if (!retval) { break; } } retval = retval && anyBlockVoxelHit; // } } else if (i == 0 && m_hitEntity is MyCubeGrid && IsSnapped /* && SnapMode == SnapMode.Base6Directions*/) { var hitGrid = m_hitEntity as MyCubeGrid; var settingsLocal = m_settings.GetGridPlacementSettings(hitGrid.GridSizeEnum, hitGrid.IsStatic); bool smallOnLargeGrid = hitGrid.GridSizeEnum == MyCubeSize.Large && grid.GridSizeEnum == MyCubeSize.Small; if (smallOnLargeGrid) { retval = retval && MyCubeGrid.TestPlacementArea(grid, ref settings, (BoundingBoxD)grid.PositionComp.LocalAABB, false); } else { retval = retval && TestGridPlacementOnGrid(grid, ref settingsLocal, hitGrid); } m_touchingGrids.Clear(); m_touchingGrids.Add(hitGrid); } else if (i == 0 && m_hitEntity is MyVoxelMap) { bool anyBlockVoxelHit = false; foreach (var block in grid.CubeBlocks) { if (block.FatBlock is MyCompoundCubeBlock) { MyCompoundCubeBlock compoundBlock = block.FatBlock as MyCompoundCubeBlock; foreach (var blockInCompound in compoundBlock.GetBlocks()) { if (!anyBlockVoxelHit) { anyBlockVoxelHit = TestVoxelPlacement(blockInCompound, ref settings, false); } retval = retval && TestBlockPlacementArea(blockInCompound, ref settings, false, false); if (!retval) { break; } } } else { if (!anyBlockVoxelHit) { anyBlockVoxelHit = TestVoxelPlacement(block, ref settings, false); } retval = retval && TestBlockPlacementArea(block, ref settings, false, false); } if (!retval) { break; } } retval = retval && anyBlockVoxelHit; Debug.Assert(i == 0); m_touchingGrids[i] = DetectTouchingGrid(); } else { var settingsLocal = m_settings.GetGridPlacementSettings(grid.GridSizeEnum, grid.IsStatic && !MyCubeBuilder.Static.DynamicMode); retval = retval && MyCubeGrid.TestPlacementArea(grid, grid.IsStatic, ref settingsLocal, (BoundingBoxD)grid.PositionComp.LocalAABB, false); } BoundingBoxD aabb = (BoundingBoxD)grid.PositionComp.LocalAABB; MatrixD invGridWorlMatrix = grid.PositionComp.WorldMatrixNormalizedInv; // Character collisions. if (MySector.MainCamera != null) { Vector3D cameraPos = Vector3D.Transform(MySector.MainCamera.Position, invGridWorlMatrix); retval = retval && aabb.Contains(cameraPos) != ContainmentType.Contains; } if (retval) { m_tmpCollisionPoints.Clear(); MyCubeBuilder.PrepareCharacterCollisionPoints(m_tmpCollisionPoints); foreach (var pt in m_tmpCollisionPoints) { Vector3D ptLocal = Vector3D.Transform(pt, invGridWorlMatrix); retval = retval && aabb.Contains(ptLocal) != ContainmentType.Contains; if (!retval) { break; } } } } return(retval); }
/// <summary> /// Returns true if the given small block connects to large one. /// </summary> /// <param name="smallBlock">small block</param> /// <param name="smallBlockWorldAabb">small block world AABB</param> /// <param name="largeBlock">large block</param> /// <param name="largeBlockWorldAabb">large block wotld AABB</param> /// <returns>true when connected</returns> private bool SmallBlockConnectsToLarge(MySlimBlock smallBlock, ref BoundingBoxD smallBlockWorldAabb, MySlimBlock largeBlock, ref BoundingBoxD largeBlockWorldAabb) { Debug.Assert(smallBlock.BlockDefinition.CubeSize == MyCubeSize.Small); Debug.Assert(largeBlock.BlockDefinition.CubeSize == MyCubeSize.Large); Debug.Assert(!(smallBlock.FatBlock is MyCompoundCubeBlock)); Debug.Assert(!(largeBlock.FatBlock is MyCompoundCubeBlock)); BoundingBoxD smallBlockWorldAabbReduced = smallBlockWorldAabb; smallBlockWorldAabbReduced.Inflate(-smallBlock.CubeGrid.GridSize / 4); // Small block aabb penetrates large block aabb (large timbers). bool penetratesAabbs = largeBlockWorldAabb.Contains(smallBlockWorldAabbReduced) == ContainmentType.Intersects; if (!penetratesAabbs) { Vector3D centerToCenter = smallBlockWorldAabb.Center - largeBlockWorldAabb.Center; Vector3I addDir = Base6Directions.GetIntVector(Base6Directions.GetClosestDirection(centerToCenter)); // Check small grid mount points Quaternion smallBlockRotation; smallBlock.Orientation.GetQuaternion(out smallBlockRotation); smallBlockRotation = Quaternion.CreateFromRotationMatrix(smallBlock.CubeGrid.WorldMatrix) * smallBlockRotation; if (!MyCubeGrid.CheckConnectivitySmallBlockToLargeGrid(largeBlock.CubeGrid, smallBlock.BlockDefinition, ref smallBlockRotation, ref addDir)) { return(false); } } BoundingBoxD smallBlockWorldAabbInflated = smallBlockWorldAabb; smallBlockWorldAabbInflated.Inflate(2 * smallBlock.CubeGrid.GridSize / 3); // Trim small block aabb with large block aabb. BoundingBoxD intersectedBox = smallBlockWorldAabbInflated.Intersect(largeBlockWorldAabb); Vector3D intersectedBoxCenter = intersectedBox.Center; HkShape shape = new HkBoxShape((Vector3)intersectedBox.HalfExtents); Quaternion largeRotation; largeBlock.Orientation.GetQuaternion(out largeRotation); largeRotation = Quaternion.CreateFromRotationMatrix(largeBlock.CubeGrid.WorldMatrix) * largeRotation; Vector3D largeTranslation; largeBlock.ComputeWorldCenter(out largeTranslation); bool result = false; try { if (largeBlock.FatBlock != null) { MyModel model = largeBlock.FatBlock.Model; if (model != null) { HkShape[] shapes = model.HavokCollisionShapes; if (shapes == null || shapes.Length == 0) { return(false); } for (int i = 0; i < shapes.Length; ++i) { result = MyPhysics.IsPenetratingShapeShape(shape, ref intersectedBoxCenter, ref Quaternion.Identity, shapes[i], ref largeTranslation, ref largeRotation); if (result) { break; } } } else { HkShape shapeLarge = new HkBoxShape(largeBlock.BlockDefinition.Size * largeBlock.CubeGrid.GridSize / 2); result = MyPhysics.IsPenetratingShapeShape(shape, ref intersectedBoxCenter, ref Quaternion.Identity, shapeLarge, ref largeTranslation, ref largeRotation); shapeLarge.RemoveReference(); } } else { HkShape shapeLarge = new HkBoxShape(largeBlock.BlockDefinition.Size * largeBlock.CubeGrid.GridSize / 2); result = MyPhysics.IsPenetratingShapeShape(shape, ref intersectedBoxCenter, ref Quaternion.Identity, shapeLarge, ref largeTranslation, ref largeRotation); shapeLarge.RemoveReference(); } } finally { shape.RemoveReference(); } return(result); }
private bool TestPlacement() { bool retval = true; for (int i = 0; i < PreviewGrids.Count; ++i) { var grid = PreviewGrids[i]; var settings = m_settings.GetGridPlacementSettings(grid); if (MySession.Static.SurvivalMode && !MyCubeBuilder.DeveloperSpectatorIsBuilding) { if (i == 0 && !MyCubeBuilder.Static.DynamicMode) { MatrixD invMatrix = grid.PositionComp.WorldMatrixNormalizedInv; if (!MyCubeBuilderGizmo.DefaultGizmoCloseEnough(ref invMatrix, (BoundingBoxD)grid.PositionComp.LocalAABB, grid.GridSize, MyCubeBuilder.Static.IntersectionDistance) || MySession.GetCameraControllerEnum() == MyCameraControllerEnum.Spectator) { m_visible = false; return(false); } } if (!MySession.Static.SimpleSurvival && MySession.ControlledEntity is MyCharacter) { foreach (var block in grid.GetBlocks()) { retval &= (MySession.ControlledEntity as MyCharacter).CanStartConstruction(block.BlockDefinition); if (!retval) { break; } } } if (i == 0 && MySession.Static.SimpleSurvival) { retval = retval && MyCubeBuilder.Static.CanBuildBlockSurvivalTime(); } if (!retval) { return(false); } } if (MyCubeBuilder.Static.DynamicMode) { if (!m_dynamicBuildAllowed) { var settingsLocal = grid.GridSizeEnum == MyCubeSize.Large ? MyPerGameSettings.PastingSettings.LargeGrid : MyPerGameSettings.PastingSettings.SmallGrid; foreach (var block in grid.GetBlocks()) { Vector3 minLocal = block.Min * PreviewGrids[i].GridSize - Vector3.Half * PreviewGrids[i].GridSize; Vector3 maxLocal = block.Max * PreviewGrids[i].GridSize + Vector3.Half * PreviewGrids[i].GridSize; BoundingBoxD aabbLocal = new BoundingBoxD(minLocal, maxLocal); retval = retval && MyCubeGrid.TestPlacementArea(grid, grid.IsStatic, ref settingsLocal, aabbLocal, true); } } } else if (i == 0 && m_hitEntity is MyCubeGrid && IsSnapped && SnapMode == MyGridPlacementSettings.SnapMode.Base6Directions) { var hitGrid = m_hitEntity as MyCubeGrid; bool smallOnLargeGrid = hitGrid.GridSizeEnum == MyCubeSize.Large && grid.GridSizeEnum == MyCubeSize.Small; if (smallOnLargeGrid) { retval = retval && MyCubeGrid.TestPlacementArea(grid, ref settings, (BoundingBoxD)grid.PositionComp.LocalAABB, false /*, hitGrid*/); } else { retval = retval && TestGridPlacementOnGrid(grid, ref settings, hitGrid); } } else if (i == 0 && m_hitEntity is MyVoxelMap) { foreach (var block in grid.CubeBlocks) { if (block.FatBlock is MyCompoundCubeBlock) { MyCompoundCubeBlock compoundBlock = block.FatBlock as MyCompoundCubeBlock; foreach (var blockInCompound in compoundBlock.GetBlocks()) { retval = retval && TestBlockPlacementArea(blockInCompound, ref settings, false); if (!retval) { break; } } } else { retval = retval && TestBlockPlacementArea(block, ref settings, false); } if (!retval) { break; } } } else { var settingsLocal = m_settings.GetGridPlacementSettings(grid, grid.IsStatic && !MyCubeBuilder.Static.DynamicMode); retval = retval && MyCubeGrid.TestPlacementArea(grid, grid.IsStatic, ref settingsLocal, (BoundingBoxD)grid.PositionComp.LocalAABB, false); } BoundingBoxD aabb = (BoundingBoxD)grid.PositionComp.LocalAABB; MatrixD invGridWorlMatrix = grid.PositionComp.GetWorldMatrixNormalizedInv(); // Character collisions. if (MySector.MainCamera != null) { Vector3D cameraPos = Vector3D.Transform(MySector.MainCamera.Position, invGridWorlMatrix); retval = retval && aabb.Contains(cameraPos) != ContainmentType.Contains; } if (retval) { m_tmpCollisionPoints.Clear(); MyCubeBuilder.PrepareCharacterCollisionPoints(m_tmpCollisionPoints); foreach (var pt in m_tmpCollisionPoints) { Vector3D ptLocal = Vector3D.Transform(pt, invGridWorlMatrix); retval = retval && aabb.Contains(ptLocal) != ContainmentType.Contains; if (!retval) { break; } } } } return(retval); }
public bool PointInsideGizmo(Vector3D point, MyGizmoSpaceEnum gizmo, ref MatrixD invGridWorldMatrix, float gridSize, float inflate = 0.0f, bool onVoxel = false) { MatrixD m = new MatrixD(); BoundingBoxD gizmoBox = new BoundingBoxD(); GetGizmoPointTestVariables(ref invGridWorldMatrix, gridSize, out gizmoBox, out m, gizmo, inflate: inflate, onVoxel: onVoxel); Vector3D localPoint = Vector3D.Transform(point, m); return gizmoBox.Contains(localPoint) == ContainmentType.Contains; }
/// <summary> /// Performes a physics raycast /// It can be recursive (it calls CastDDA when it hits a grid). /// </summary> /// <param name="fromWorldPos"></param> /// <returns>Returns starting damage for current stack</returns> private MyRaycastDamageInfo CastPhysicsRay(Vector3D fromWorldPos) { Vector3D pos = Vector3D.Zero; IMyEntity hitEntity = null; var hitInfo = MyPhysics.CastRay(fromWorldPos, m_explosion.Center, MyPhysics.ExplosionRaycastLayer); if (hitInfo.HasValue) { hitEntity = (hitInfo.Value.HkHitInfo.Body.UserObject != null) ? ((MyPhysicsBody)hitInfo.Value.HkHitInfo.Body.UserObject).Entity : null; pos = hitInfo.Value.Position; } Vector3D direction = (m_explosion.Center - fromWorldPos); float lengthToCenter = (float)direction.Length(); direction.Normalize(); var grid = (hitEntity as MyCubeGrid); if (grid == null) { MyCubeBlock hitBlock = hitEntity as MyCubeBlock; if (hitBlock != null) { grid = hitBlock.CubeGrid; } } if (grid != null) { //Try advancing the point to find the intersected block //If the block is a cube, this is necessary because the raycast will return a point somewhere outside the cube //If the block is not a full cube (slope, special block), the raycast can return inside the cube //It advances 4 times, each time one 8th the grid size for (int i = 0; i < 5; i++) { Vector3D localPos = Vector3D.Transform(pos, grid.PositionComp.WorldMatrixNormalizedInv) / grid.GridSize; Vector3I gridPos = Vector3I.Round(localPos); var cubeBlock = grid.GetCubeBlock(gridPos); if (cubeBlock != null) { if (m_castBlocks.Contains(cubeBlock)) { //This shouldn't happen //There is a corner case where the explosion position is inside the empty cell, but this should be handleded somewhere higher System.Diagnostics.Debug.Fail("Raycast failed!"); DrawRay(fromWorldPos, pos, Color.Red); return(new MyRaycastDamageInfo(0f, lengthToCenter)); } else { if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Blue); } return(CastDDA(cubeBlock)); } } pos += direction * grid.GridSize / 8f; } //We hit a grid but were unable to find the hit cube. Send another raycast //Ideally, we would want to get the cube in all cases, but it also has to be fast //We need to check if the explosion center is between the initial start position (fromWorldPos) and the new one (pos) Vector3D min = new Vector3D(Math.Min(fromWorldPos.X, pos.X), Math.Min(fromWorldPos.Y, pos.Y), Math.Min(fromWorldPos.Z, pos.Z)); Vector3D max = new Vector3D(Math.Max(fromWorldPos.X, pos.X), Math.Max(fromWorldPos.Y, pos.Y), Math.Max(fromWorldPos.Z, pos.Z)); BoundingBoxD boundingBox = new BoundingBoxD(min, max); if (boundingBox.Contains(m_explosion.Center) == ContainmentType.Contains) { return(new MyRaycastDamageInfo(m_explosionDamage, lengthToCenter)); } stackOverflowGuard++; if (stackOverflowGuard > MAX_PHYSICS_RECURSION_COUNT) { System.Diagnostics.Debug.Fail("Potential stack overflow!"); if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Red); } return(new MyRaycastDamageInfo(0f, lengthToCenter)); } else { if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.White); } return(CastPhysicsRay(pos)); } } else if (hitInfo.HasValue) { //Something was hit, but it wasn't a grid. This needs to be handled somehow if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Violet); } return(new MyRaycastDamageInfo(0, lengthToCenter)); } //Nothing was hit, so we can assume the there was nothing blocking the explosion if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Salmon); } return(new MyRaycastDamageInfo(m_explosionDamage, lengthToCenter)); }
private static bool IsInCell(ref BoundingBoxD cellbox, ref BoundingSphereD asteroid) { return cellbox.Contains(asteroid) != ContainmentType.Disjoint; }
private static bool IsInCell(ref BoundingBoxD cellbox, ref BoundingSphereD asteroid) { return(cellbox.Contains(asteroid) != ContainmentType.Disjoint); }