public static void GetExistingCubes(MyCubeGrid grid, Vector3I min, Vector3I max, BoundingSphere localSphere, bool checkDestroyed, List <IMySlimBlock> resultSet) { resultSet.Clear(); Vector3I result1 = Vector3I.Floor((min - Vector3I.One) / 2f); Vector3I result2 = Vector3I.Ceiling((max - Vector3I.One) / 2f); var gridMin = grid.Min; var gridMax = grid.Max; Vector3I.Max(ref result1, ref gridMin, out result1); Vector3I.Min(ref result2, ref gridMax, out result2); Vector3I key; for (key.X = result1.X; key.X <= result2.X; ++key.X) { for (key.Y = result1.Y; key.Y <= result2.Y; ++key.Y) { for (key.Z = result1.Z; key.Z <= result2.Z; ++key.Z) { MyCube myCube; if (grid.TryGetCube(key, out myCube)) { var block = (IMySlimBlock)myCube.CubeBlock; if (checkDestroyed && block.IsDestroyed || !new BoundingBox(block.Min * grid.GridSize - grid.GridSizeHalf, block.Max * grid.GridSize + grid.GridSizeHalf).Intersects(localSphere)) { continue; } resultSet.Add(block); } } } } }
public static void GetExistingCubes(MyCubeGrid grid, Vector3I min, Vector3I max, List <IMySlimBlock> resultSet) { resultSet.Clear(); Vector3I result1 = Vector3I.Floor((min - Vector3I.One) / 2f); Vector3I result2 = Vector3I.Ceiling((max - Vector3I.One) / 2f); var gridMin = grid.Min; var gridMax = grid.Max; Vector3I.Max(ref result1, ref gridMin, out result1); Vector3I.Min(ref result2, ref gridMax, out result2); Vector3I key; for (key.X = result1.X; key.X <= result2.X; ++key.X) { for (key.Y = result1.Y; key.Y <= result2.Y; ++key.Y) { for (key.Z = result1.Z; key.Z <= result2.Z; ++key.Z) { MyCube myCube; if (grid.TryGetCube(key, out myCube)) { resultSet.Add(myCube.CubeBlock); } } } } }
private static bool IntersectsVoxelSurface(OrientedBoundingBoxD box) { var data = VoxelData; using (PoolManager.Get(out List <MyEntity> entities)) { MyGamePruningStructure.GetTopmostEntitiesInBox(box.GetAABB(), entities, MyEntityQueryType.Static); foreach (var ent in entities) { if (ent is MyVoxelBase voxel && !(ent is MyVoxelPhysics)) { var invWorld = voxel.PositionComp.WorldMatrixInvScaled; var storageBounds = BoundingBoxD.CreateInvalid(); var voxelOffset = (voxel.Size >> 1) + voxel.StorageMin; var storageObb = box; storageObb.Transform(invWorld); storageObb.HalfExtent /= voxel.VoxelSize; storageObb.Center = storageObb.Center / voxel.VoxelSize + voxelOffset; storageBounds.Include(storageObb.GetAABB()); var storageMin = Vector3I.Max(Vector3I.Floor(storageBounds.Min), voxel.StorageMin); var storageMax = Vector3I.Min(Vector3I.Ceiling(storageBounds.Max), voxel.StorageMax); var localBox = new BoundingBoxI(storageMin, storageMax); localBox.Inflate(1); var floatBox = new BoundingBox(localBox); if (voxel.IntersectStorage(ref floatBox) == ContainmentType.Disjoint) { continue; } data.Resize(storageMin, storageMax); voxel.Storage.ReadRange(data, MyStorageDataTypeFlags.Content, 0, storageMin, storageMax); foreach (var pt in new BoundingBoxI(Vector3I.Zero, storageMax - storageMin).EnumeratePoints()) { var voxelBox = new BoundingBoxD(storageMin + pt, storageMin + pt + 1); var containment = storageObb.Contains(ref voxelBox); if (containment == ContainmentType.Disjoint) { continue; } var tmpPt = pt; var index = data.ComputeLinear(ref tmpPt); var content = data.Content(index); if (containment == ContainmentType.Intersects && content >= 127) { return(true); } if (containment == ContainmentType.Contains && content > 0) { return(true); } } } } } return(false); }
public override MyVoxelMaterialDefinition GetMaterialForPosition(ref Vector3 pos, float lodSize) { Vector3I cellPos = Vector3I.Ceiling(pos / DEPOSIT_MAX_SIZE); MyCompositeShapeOreDeposit deposit; if (m_deposits.TryGetValue(cellPos, out deposit) == true) { if (deposit.Shape.SignedDistance(ref pos, lodSize, null, null) == -1) { return(deposit.GetMaterialForPosition(ref pos, lodSize)); } } return(null); }
public MyCompositeOrePlanetDeposit(MyCsgShapeBase baseShape, int seed, float minDepth, float maxDepth, MyOreProbability[] oreProbabilties, MyVoxelMaterialDefinition material) : base(baseShape, material) { m_minDepth = minDepth; double outherSphereVolume = (4.0 * MathHelper.Pi * Math.Pow(minDepth, 3.0f)) / 3.0; double innerSphereVolume = (4.0 * MathHelper.Pi * Math.Pow(maxDepth, 3.0f)) / 3.0; double depositVolume = (4.0 * MathHelper.Pi * Math.Pow(DEPOSIT_MAX_SIZE, 3.0f)) / 3.0; double volume = outherSphereVolume - innerSphereVolume; m_numDeposits = oreProbabilties.Length > 0 ? (int)Math.Floor((volume * 0.4f) / depositVolume) : 0; int numSectors = (int)(minDepth / DEPOSIT_MAX_SIZE); MyRandom random = MyRandom.Instance; FillMaterialCollections(); Vector3D offset = -new Vector3D(DEPOSIT_MAX_SIZE / 2.0); using (var stateToken = random.PushSeed(seed)) { for (int i = 0; i < m_numDeposits; ++i) { Vector3D direction = MyProceduralWorldGenerator.GetRandomDirection(random); float distanceFromCenter = random.NextFloat(maxDepth, minDepth); Vector3D position = direction * distanceFromCenter; Vector3I cellPos = Vector3I.Ceiling((Shape.Center() + position) / DEPOSIT_MAX_SIZE); MyCompositeShapeOreDeposit deposit; if (m_deposits.TryGetValue(cellPos, out deposit) == false) { var oreDefinition = GetOre(random.NextFloat(0, 1), oreProbabilties); var materialDefinition = m_materialsByOreType[oreDefinition.OreName][random.Next() % m_materialsByOreType[oreDefinition.OreName].Count]; deposit = new MyCompositeShapeOreDeposit(new MyCsgSimpleSphere(cellPos * DEPOSIT_MAX_SIZE + offset, random.NextFloat(64, DEPOSIT_MAX_SIZE / 2.0f)), materialDefinition); m_deposits[cellPos] = deposit; } } } m_materialsByOreType.Clear(); }
/// <summary> /// Calculates amount of volume of a bounding box in voxels. /// </summary> /// <param name="localAabb">Local bounding box to query for.</param> /// <param name="worldMatrix">World matrix of the bounding box.</param> /// <returns>Pair of floats where 1st value is Volume amount and 2nd value is ratio of Volume amount to Whole volume.</returns> public MyTuple <float, float> GetVoxelContentInBoundingBox_Fast(BoundingBoxD localAabb, MatrixD worldMatrix) { MatrixD toVoxel = worldMatrix * PositionComp.WorldMatrixNormalizedInv; MatrixD toGrid; MatrixD.Invert(ref toVoxel, out toGrid); BoundingBoxD transAABB = localAabb.Transform(toVoxel); transAABB.Translate(SizeInMetresHalf + StorageMin); Vector3I minI = Vector3I.Floor(transAABB.Min); Vector3I maxI = Vector3I.Ceiling(transAABB.Max); double vol = localAabb.Volume / MyVoxelConstants.VOXEL_VOLUME_IN_METERS; int K = Math.Max((MathHelper.Log2Ceiling((int)vol) - MathHelper.Log2Ceiling(100)) / 3, 0); float voxelSizeAtLod = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << K); float voxelVolumeAtLod = voxelSizeAtLod * voxelSizeAtLod * voxelSizeAtLod; minI >>= K; maxI >>= K; // localAabb.Inflate(1 * voxelSizeAtLod); var offset = ((Size >> 1) + StorageMin) >> K; m_tempStorage.Resize(maxI - minI + 1); Storage.ReadRange(m_tempStorage, MyStorageDataTypeFlags.Content, K, minI, maxI); float resultVolume = 0; float resultPercent = 0; int hitVolumeBoxes = 0; MyOrientedBoundingBoxD worldbbox = new MyOrientedBoundingBoxD(localAabb, worldMatrix); Vector3I coord, cache; for (coord.Z = minI.Z, cache.Z = 0; coord.Z <= maxI.Z; coord.Z++, cache.Z++) { for (coord.Y = minI.Y, cache.Y = 0; coord.Y <= maxI.Y; coord.Y++, cache.Y++) { for (coord.X = minI.X, cache.X = 0; coord.X <= maxI.X; coord.X++, cache.X++) { Vector3D voxelPos = (coord - offset) * voxelSizeAtLod; Vector3D gridPoint; Vector3D.Transform(ref voxelPos, ref toGrid, out gridPoint); ContainmentType cont; //localAabb.Contains(ref gridPoint, out cont); var voxelToWorld = WorldMatrix; voxelToWorld.Translation -= (Vector3D)StorageMin + SizeInMetresHalf; BoundingBoxD voxelBox = new BoundingBoxD(); voxelBox.Min = ((Vector3D)(coord) - .5) * voxelSizeAtLod; voxelBox.Max = ((Vector3D)(coord) + .5) * voxelSizeAtLod; MyOrientedBoundingBoxD voxelBbox = new MyOrientedBoundingBoxD(voxelBox, voxelToWorld); cont = worldbbox.Contains(ref voxelBbox); if (cont == ContainmentType.Disjoint) { //VRageRender.MyRenderProxy.DebugDrawOBB( //new MyOrientedBoundingBoxD(voxelBox, voxelToWorld), Color.Red, 0.1f, //true, false); continue; } float content = m_tempStorage.Content(ref cache) / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT; //VRageRender.MyRenderProxy.DebugDrawOBB(voxelBbox, Color.Aqua, content, // true, false); resultVolume += content * voxelVolumeAtLod; resultPercent += content; hitVolumeBoxes++; } } } resultPercent /= hitVolumeBoxes; //float localAABBVol = (float)localAabb.Volume; //if (localAABBVol < resultVolume) // resultPercent *= (float)localAabb.Volume / resultVolume; //VRageRender.MyRenderProxy.DebugDrawOBB(worldbbox, Color.Yellow, 0, // true, false); //VRageRender.MyRenderProxy.DebugWaitForFrameFinish(); return(new MyTuple <float, float>(resultVolume, resultPercent)); }
public void Apply(IReadOnlyList <IMyCubeGrid> group) { var totalAABB = BoundingBoxD.CreateInvalid(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var grid in group) { totalAABB = totalAABB.Include(grid.WorldAABB); } var totalSphere = new BoundingSphereD(totalAABB.Center, totalAABB.HalfExtents.Length()); foreach (var impact in m_impactDirectionRadius) { var speed = impact.Velocity.Length(); var direction = (Vector3D)impact.Velocity / speed; Vector3D start, end; { var rayOffset = totalAABB.HalfExtents * 0.8 * (Vector3D)impact.Shift; // mag2(rayOffset + l*direction) == radius*radius // (rayOffset + l*direction)*(rayOffset + l*direction) // mag2(rayOffset) + 2*l*dot(direction, rayOffset) + l*l*mag2(direction) // mag2(rayOffset) - (radius*radius) + 2*l*dot(direction, rayOffset) + l*l == 0 var c = rayOffset.LengthSquared() - totalSphere.Radius * totalSphere.Radius; var b = 2 * Vector3D.Dot(direction, rayOffset); const float a = 1; var rad = b * b - 4 * a * c; if (rad <= double.Epsilon) { continue; } var lLow = (-b - Math.Sqrt(rad)) / (2 * a); var lHigh = (-b + Math.Sqrt(rad)) / (2 * a); start = totalSphere.Center + rayOffset + lLow * direction; end = totalSphere.Center + rayOffset + lHigh * direction; } var ray = new RayD(start, direction); var bestHitLocation = default(Vector3D); var bestHitDistanceSquared = double.MaxValue; foreach (var grid in group) { if (!grid.WorldAABB.Intersects(ray).HasValue) { continue; } var block = grid.RayCastBlocks(start, end); if (!block.HasValue) { continue; } var world = Vector3D.Transform(block.Value * grid.GridSize, grid.WorldMatrix); var distance = Vector3D.DistanceSquared(world, start); if (distance > bestHitDistanceSquared) { continue; } bestHitDistanceSquared = distance; bestHitLocation = world; } if (bestHitDistanceSquared > double.MaxValue / 2) { continue; } var impactSphere = new BoundingSphereD(bestHitLocation, impact.Radius); var localSphere = new BoundingSphereD(); var damageAmount = impact.Mass * speed * speed * (4.0 / 3.0) * Math.PI; var damageTotals = new Dictionary <IMySlimBlock, double>(); foreach (var grid in group) { if (grid.WorldAABB.Intersects(impactSphere)) { // compute local sphere. localSphere.Center = Vector3D.Transform(impactSphere.Center, grid.WorldMatrixNormalizedInv) / grid.GridSize; localSphere.Radius = impactSphere.Radius / grid.GridSize; var min = Vector3I.Max(Vector3I.Floor(localSphere.Center - localSphere.Radius), grid.Min); var max = Vector3I.Min(Vector3I.Ceiling(localSphere.Center + localSphere.Radius), grid.Max); for (var itr = new Vector3I_RangeIterator(ref min, ref max); itr.IsValid(); itr.MoveNext()) { if (localSphere.Contains(itr.Current) == ContainmentType.Disjoint) { continue; } var block = grid.GetCubeBlock(itr.Current); if (block == null) { continue; } var distanceFactor = 1 - ((Vector3D)itr.Current - localSphere.Center).LengthSquared() / (localSphere.Radius * localSphere.Radius); var blockDamage = damageAmount * distanceFactor * ((block.BlockDefinition as MyCubeBlockDefinition)?.DeformationRatio ?? 1); damageTotals.AddValue(block, blockDamage); } } } // No idea what shape key should be. Logger.Debug("Apply damage to {0} blocks", damageTotals.Count); var hitInfo = new MyHitInfo() { Normal = direction, Position = impactSphere.Center, Velocity = impact.Velocity, ShapeKey = 0 }; foreach (var kv in damageTotals) { kv.Key.DoDamage((float)kv.Value, MyDamageType.Explosion, true, hitInfo); } } }
private static bool IntersectsInternalExpensive(ref PartFromPrefab partA, ref MatrixI transformA, ref MatrixI invTransformA, ref PartFromPrefab partB, ref MatrixI transformB, ref MatrixI invTransformB, bool testOptional) { using (partA.LockSharedUsing()) using (partB.LockSharedUsing()) { var reservedAAll = Utilities.TransformBoundingBox(partA.ReservedSpace, ref transformA); var reservedBAll = Utilities.TransformBoundingBox(partB.ReservedSpace, ref transformB); var reservedA = new List <MyTuple <ReservedSpace, BoundingBox> >(partA.m_reservedSpaces.Count); // ReSharper disable once LoopCanBeConvertedToQuery (preserve ref) foreach (var aabb in partA.m_reservedSpaces) { if (!aabb.IsOptional || testOptional) { reservedA.Add(MyTuple.Create(aabb, Utilities.TransformBoundingBox(aabb.Box, ref transformA))); } } var reservedB = new List <MyTuple <ReservedSpace, BoundingBox> >(partB.m_reservedSpaces.Count); // ReSharper disable once LoopCanBeConvertedToQuery (preserve ref) foreach (var aabb in partB.m_reservedSpaces) { if (!aabb.IsOptional || testOptional) { reservedB.Add(MyTuple.Create(aabb, Utilities.TransformBoundingBox(aabb.Box, ref transformB))); } } // Reserved spaces intersect? if (partA.m_reservedSpaces.Count > 0 && partB.m_reservedSpaces.Count > 0 && reservedAAll.Intersects(reservedBAll)) { if (reservedA.Any(x => reservedB.Any(y => !y.Item1.IsShared && !x.Item1.IsShared && x.Item2.Intersects(y.Item2)))) { return(true); } } var blockAAll = Utilities.TransformBoundingBox(partA.BoundingBox, ref transformA); var blockBAll = Utilities.TransformBoundingBox(partB.BoundingBox, ref transformB); // Block spaces intersect with reserved space? if (partA.m_reservedSpaces.Count > 0 && reservedAAll.Intersects(blockBAll)) { foreach (var aabb in reservedA) { var min = Vector3I.Floor(Vector3.Max(aabb.Item2.Min, blockBAll.Min)); var max = Vector3I.Ceiling(Vector3.Min(aabb.Item2.Max, blockBAll.Max)); for (var vi = new Vector3I_RangeIterator(ref min, ref max); vi.IsValid(); vi.MoveNext()) { if (partB.CubeExists(Vector3I.Transform(vi.Current, invTransformB))) { return(true); } } } } if (partB.m_reservedSpaces.Count > 0 && reservedBAll.Intersects(blockAAll)) { foreach (var aabb in reservedB) { var min = Vector3I.Floor(Vector3.Max(aabb.Item2.Min, blockAAll.Min)); var max = Vector3I.Ceiling(Vector3.Min(aabb.Item2.Max, blockAAll.Max)); for (var vi = new Vector3I_RangeIterator(ref min, ref max); vi.IsValid(); vi.MoveNext()) { if (partA.CubeExists(Vector3I.Transform(vi.Current, invTransformA))) { return(true); } } } } // Block space intersects with block space? if (!blockAAll.Intersects(blockBAll)) { return(false); } if (partA.m_blocks.Count < partB.m_blocks.Count) { foreach (var pos in partA.m_blocks.Keys) { if (partB.CubeExists(Vector3I.Transform(Vector3I.Transform(pos, ref transformA), ref invTransformB))) { return(true); } } } else { foreach (var pos in partB.m_blocks.Keys) { if (partA.CubeExists(Vector3I.Transform(Vector3I.Transform(pos, ref transformB), ref invTransformA))) { return(true); } } } return(false); } }
private bool ApplyDelegate(MyObjectBuilder_CubeGrid grid, MyObjectBuilder_CubeBlock source, string srcName, MyObjectBuilder_CubeBlock dest, Base6Directions.Direction destDir) { if (srcName.StartsWithICase(MountDelegated)) { var lTransOrig = new MatrixI(source.BlockOrientation); var lTrans = new MatrixI(dest.BlockOrientation); MatrixI iTrans; MatrixI.Invert(ref lTrans, out iTrans); var arguments = PartDummyUtils.ConfigArguments(srcName.Substring(MountDelegated.Length).Trim()).Select( (arg) => { if (arg.StartsWithICase(PartDummyUtils.ArgumentBiasDirection)) { Base6Directions.Direction dir; if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentBiasDirection.Length), out dir)) { return(PartDummyUtils.ArgumentBiasDirection + iTrans.GetDirection(lTransOrig.GetDirection(dir))); } else { this.Error("Failed to parse bias argument \"{0}\"", arg); } } else if (arg.StartsWithICase(PartDummyUtils.ArgumentSecondBiasDirection)) { Base6Directions.Direction dir; if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentSecondBiasDirection.Length), out dir)) { return(PartDummyUtils.ArgumentSecondBiasDirection + iTrans.GetDirection(lTransOrig.GetDirection(dir))); } else { this.Error("Failed to parse second bias argument \"{0}\"", arg); } } return(arg); }).ToList(); arguments.Add(PartDummyUtils.ArgumentMountDirection + iTrans.GetDirection(Base6Directions.GetOppositeDirection(destDir))); var anchorPoint = source.Min + Base6Directions.GetIntVector(destDir); var del = anchorPoint - dest.Min; if (del != Vector3I.Zero) { arguments.Add(PartDummyUtils.ArgumentAnchorPoint + del.X + ":" + del.Y + ":" + del.Z); } var outName = PartMetadata.MountPrefix + " " + string.Join(" ", arguments); if (string.IsNullOrWhiteSpace(dest.Name)) { dest.Name = outName; } else { dest.Name = dest.Name + PartMetadata.MultiUseSentinel + outName; } return(true); } if (srcName.StartsWithICase(ReservedSpaceDelegated)) { var baseName = srcName.Substring(ReservedSpaceDelegated.Length).Trim(); var args = baseName.Split(' ').Select(x => x.Trim()).Where(x => x.Length > 0).ToArray(); var box = PartDummyUtils.ParseReservedSpace(MyDefinitionManager.Static.GetCubeSize(grid.GridSizeEnum), source, args, this.Error); var del = source.Min - (Vector3I)dest.Min; box.Box.Max += del; box.Box.Min += del; var boxLocalFloat = Utilities.TransformBoundingBox(box.Box, Matrix.Invert(new MatrixI(dest.BlockOrientation).GetFloatMatrix())); var boxLocal = new BoundingBoxI(Vector3I.Floor(boxLocalFloat.Min), Vector3I.Ceiling(boxLocalFloat.Max)); var outName = $"{PartMetadata.ReservedSpacePrefix} NE:{boxLocal.Min.X}:{boxLocal.Min.Y}:{boxLocal.Min.Z} PE:{boxLocal.Max.X}:{boxLocal.Max.Y}:{boxLocal.Max.Z}"; if (box.IsShared) { outName += " shared"; } if (box.IsOptional) { outName += " optional"; } if (string.IsNullOrWhiteSpace(dest.Name)) { dest.Name = outName; } else { dest.Name = dest.Name + PartMetadata.MultiUseSentinel + outName; } return(true); } return(false); }
private void Process(CommandFeedback feedback, IMyCubeGrid grid) { if (grid.CustomName == null || !grid.CustomName.StartsWithICase("EqProcBuild")) { return; } var ob = grid.GetObjectBuilder(true) as MyObjectBuilder_CubeGrid; if (ob == null) { return; } this.Info("Begin processing {0}", grid.CustomName); feedback?.Invoke("Processing {0}", grid.CustomName); try { var dummyDel = new List <MyTuple <MyObjectBuilder_CubeBlock, string> >(); var blockKeep = new List <MyObjectBuilder_CubeBlock>(); var blockMap = new Dictionary <Vector3I, MyObjectBuilder_CubeBlock>(Vector3I.Comparer); foreach (var block in ob.CubeBlocks) { var mount = false; foreach (var name in block.ConfigNames()) { if (!name.StartsWithICase(MountDelegated) && !name.StartsWithICase(ReservedSpaceDelegated)) { continue; } dummyDel.Add(MyTuple.Create(block, name)); mount = true; break; } if (mount) { continue; } var blockMin = (Vector3I)block.Min; Vector3I blockMax; BlockTransformations.ComputeBlockMax(block, out blockMax); for (var rangeItr = new Vector3I_RangeIterator(ref blockMin, ref blockMax); rangeItr.IsValid(); rangeItr.MoveNext()) { blockMap[rangeItr.Current] = block; } blockKeep.Add(block); } this.Info("Found {0} blocks to keep, {1} block mounts to remap", blockKeep.Count, dummyDel.Count); foreach (var pair in dummyDel) { var block = pair.Item1; var useName = pair.Item2; IEnumerable <Base6Directions.Direction> dirs = Base6Directions.EnumDirections; var def = MyDefinitionManager.Static.GetCubeBlockDefinition(pair.Item1); var transform = new MatrixI(block.BlockOrientation); if (def?.MountPoints != null) { var mountDirs = new HashSet <Base6Directions.Direction>(); foreach (var mount in def.MountPoints) { mountDirs.Add(Base6Directions.GetDirection(Vector3I.TransformNormal(mount.Normal, ref transform))); } } var args = useName.Split(' '); var keepArgs = new List <string>(args.Length); foreach (var arg in args) { if (arg.StartsWithICase(PartDummyUtils.ArgumentMountDirection)) { Base6Directions.Direction dir; if (Enum.TryParse(arg.Substring(2), out dir)) { dirs = new[] { transform.GetDirection(Base6Directions.GetOppositeDirection(dir)) } } ; else { this.Error("Failed to parse direction argument \"{0}\"", arg); feedback?.Invoke("Error: Failed to parse direction argument \"{0}\"", arg); } } else { keepArgs.Add(arg); } } useName = string.Join(" ", keepArgs); MyObjectBuilder_CubeBlock outputBlock = null; var outputDir = Base6Directions.Direction.Forward; foreach (var dir in dirs) { MyObjectBuilder_CubeBlock tmp; if (!blockMap.TryGetValue(block.Min + Base6Directions.GetIntVector(dir), out tmp)) { continue; } if (tmp.ConfigNames().Any(x => x.StartsWithICase(MountDelegated))) { continue; } if (outputBlock != null) { this.Error("Multiple directions found for {0}", pair.Item2); feedback?.Invoke("Error: Multiple directions found for {0}", pair.Item2); } outputBlock = tmp; outputDir = dir; } if (outputBlock == null || !ApplyDelegate(ob, block, useName, outputBlock, outputDir)) { this.Error("Failed to find delegated mount point for {0}", pair.Item2); feedback?.Invoke("Error: Failed to find delegated mount point for {0}", pair.Item2); } } ob.CubeBlocks = blockKeep; // Grab related grids! var relatedGrids = new HashSet <IMyCubeGrid> { grid }; var scanRelated = new Queue <IMyCubeGrid>(); var relatedGridController = new Dictionary <IMyCubeGrid, IMyCubeBlock>(); scanRelated.Enqueue(grid); while (scanRelated.Count > 0) { var subGrid = scanRelated.Dequeue(); IMyCubeBlock controllerForThisGrid = null; relatedGridController.TryGetValue(subGrid, out controllerForThisGrid); subGrid.GetBlocks(null, (y) => { var x = y?.FatBlock; if (x == null) { return(false); } var childGrid = (x as IMyMechanicalConnectionBlock)?.TopGrid; if (childGrid != null && relatedGrids.Add(childGrid)) { scanRelated.Enqueue(childGrid); relatedGridController[childGrid] = x.CubeGrid == grid ? x : controllerForThisGrid; } var parentGrid = (x as IMyAttachableTopBlock)?.Base?.CubeGrid; // ReSharper disable once InvertIf if (parentGrid != null && relatedGrids.Add(parentGrid)) { scanRelated.Enqueue(parentGrid); relatedGridController[parentGrid] = x.CubeGrid == grid ? x : controllerForThisGrid; } return(false); }); } relatedGrids.Remove(grid); var removedNoController = relatedGrids.RemoveWhere(x => !relatedGridController.ContainsKey(x)); if (removedNoController > 0) { this.Error("Failed to find the mechanical connection block for all subgrids. {0} will be excluded", removedNoController); feedback?.Invoke("Error: Failed to find the mechanical connection block for all subgrids. {0} will be excluded", removedNoController); } // Need to add reserved space for subgrids so they don't overlap. So compute that. Yay! foreach (var rel in relatedGrids) { IMyCubeBlock root; if (!relatedGridController.TryGetValue(rel, out root)) { this.Error("Unable to find the mechanical connection for grid {0}", rel.CustomName); feedback?.Invoke("Error: Unable to find the mechanical connection for grid {0}", rel.CustomName); continue; } MyObjectBuilder_CubeBlock blockDest; if (blockMap.TryGetValue(root.Min, out blockDest)) { var blockLocal = (MatrixD) new MatrixI(blockDest.BlockOrientation).GetFloatMatrix(); blockLocal.Translation = (Vector3I)blockDest.Min * grid.GridSize; var blockWorld = MatrixD.Multiply(blockLocal, grid.WorldMatrix); var worldAABB = rel.WorldAABB; worldAABB = Utilities.TransformBoundingBox(worldAABB, MatrixD.Invert(blockWorld)); var gridAABB = new BoundingBoxI(Vector3I.Floor(worldAABB.Min / grid.GridSize), Vector3I.Ceiling(worldAABB.Max / grid.GridSize)); var code = $"{PartMetadata.ReservedSpacePrefix} NE:{gridAABB.Min.X}:{gridAABB.Min.Y}:{gridAABB.Min.Z} PE:{gridAABB.Max.X}:{gridAABB.Max.Y}:{gridAABB.Max.Z}"; this.Info("Added reserved space for subgrid {0}: Spec is \"{1}\"", rel.CustomName, code); if (blockDest.Name == null || blockDest.Name.Trim().Length == 0) { blockDest.Name = code; } else { blockDest.Name += PartMetadata.MultiUseSentinel + code; } } else { this.Error("Unable to find the OB for grid block {0} ({1}, {2}, {3}). Is it a delegate?", (root as IMyTerminalBlock)?.CustomName ?? root.Name, root.Min.X, root.Min.Y, root.Min.Z); feedback?.Invoke("Unable to the find OB for grid block {0} ({1}, {2}, {3}). Was it a delegate?", (root as IMyTerminalBlock)?.CustomName ?? root.Name, root.Min.X, root.Min.Y, root.Min.Z); } } var allGrids = new List <MyObjectBuilder_CubeGrid>(relatedGrids.Count + 1) { ob }; allGrids.AddRange(relatedGrids.Select(relGrid => relGrid.GetObjectBuilder(false)).OfType <MyObjectBuilder_CubeGrid>()); // Compose description: TODO I'd love if this actually worked :/ // var storage = new MyPartMetadata(); // storage.InitFromGrids(ob, allGrids); // var data = Convert.ToBase64String(MyAPIGateway.Utilities.SerializeToBinary(storage.GetObjectBuilder())); var defOut = new MyObjectBuilder_PrefabDefinition() { Id = new SerializableDefinitionId(typeof(MyObjectBuilder_PrefabDefinition), grid.CustomName), CubeGrids = allGrids.ToArray() }; var fileName = grid.CustomName + ".sbc"; this.Info("Saving {1} grids as {0}", fileName, defOut.CubeGrids.Length); feedback?.Invoke("Saving {1} grids as {0}", fileName, defOut.CubeGrids.Length); var mishMash = new MyObjectBuilder_Definitions() { Prefabs = new MyObjectBuilder_PrefabDefinition[] { defOut } }; var writer = MyAPIGateway.Utilities.WriteBinaryFileInLocalStorage(fileName, typeof(DesignTools)); var obCode = MyAPIGateway.Utilities.SerializeToXML(mishMash); obCode = obCode.Replace("encoding=\"utf-16\"", "encoding=\"utf-8\""); writer.Write(Encoding.UTF8.GetBytes(obCode)); writer.Close(); } catch (Exception e) { this.Error("Failed to parse. Error:\n{0}", e.ToString()); } }
private static int PerformVoxelOpInternal( List <MyVoxelBase> voxels, List <OrientedBoundingBoxD> boxes, byte replacementMaterial, int materialLimit, VoxelMiningBuffer miningBuffer, bool disableFarmingItems) { var data = VoxelData; var usedMaterial = 0; using (PoolManager.Get(out List <OrientedBoundingBoxD> storageBoxes)) foreach (var voxel in voxels) { if (materialLimit < usedMaterial) { break; } var invWorld = voxel.PositionComp.WorldMatrixInvScaled; var storageBounds = BoundingBoxD.CreateInvalid(); storageBoxes.Clear(); var voxelOffset = (voxel.Size >> 1) + voxel.StorageMin; foreach (var obb in boxes) { var storageObb = obb; storageObb.Transform(invWorld); storageObb.HalfExtent /= voxel.VoxelSize; storageObb.Center = storageObb.Center / voxel.VoxelSize + voxelOffset; storageBoxes.Add(storageObb); storageBounds.Include(storageObb.GetAABB()); } var storageMin = Vector3I.Max(Vector3I.Floor(storageBounds.Min), voxel.StorageMin); var storageMax = Vector3I.Min(Vector3I.Ceiling(storageBounds.Max), voxel.StorageMax); var localBox = new BoundingBox(storageMin, storageMax); localBox.Translate(-voxel.SizeInMetresHalf - voxel.StorageMin); if (voxel.IntersectStorage(ref localBox, false) == ContainmentType.Disjoint) { continue; } data.Resize(storageMin, storageMax); voxel.Storage.ReadRange(data, MyStorageDataTypeFlags.ContentAndMaterial, 0, storageMin, storageMax); var modified = false; var modifiedVoxels = BoundingBoxD.CreateInvalid(); foreach (var pt in new BoundingBoxI(Vector3I.Zero, storageMax - storageMin).EnumeratePoints()) { if (materialLimit < usedMaterial) { break; } var contained = false; var voxelBox = new BoundingBoxD(storageMin + pt, storageMin + pt + 1); foreach (var storageBox in storageBoxes) { if (storageBox.Intersects(ref voxelBox)) { contained = true; break; } } if (!contained) { continue; } var tmpPt = pt; var index = data.ComputeLinear(ref tmpPt); var content = data.Content(index); if (content <= 0) { continue; } var material = data.Material(index); if (material == replacementMaterial) { continue; } usedMaterial += content; miningBuffer?.Add(material, content); data.Material(index, replacementMaterial); modified = true; modifiedVoxels.Include(voxelBox); } if (!modified) { continue; } voxel.Storage.WriteRange(data, MyStorageDataTypeFlags.Material, storageMin, storageMax); if (!disableFarmingItems) { continue; } modifiedVoxels.Min = (modifiedVoxels.Min - voxelOffset) * voxel.VoxelSize; modifiedVoxels.Max = (modifiedVoxels.Max - voxelOffset) * voxel.VoxelSize; voxel.DisableFarmingItemsIn(OrientedBoundingBoxD.Create(modifiedVoxels, voxel.WorldMatrix)); } return(usedMaterial); }
public override IEnumerable <ProceduralObject> Generate(BoundingSphereD include, BoundingSphereD?exclude) { var root = Vector3D.Transform(include.Center, m_invTransform); var excludeRoot = exclude.HasValue ? Vector3D.Transform(exclude.Value.Center, m_invTransform) : default(Vector3D); var minLocal = root - include.Radius; var maxLocal = root + include.Radius; minLocal = Vector3D.Max(minLocal, Shape.RelevantArea.Min); maxLocal = Vector3D.Min(maxLocal, Shape.RelevantArea.Max); for (var i = 0; i < m_layers.Length; i++) { var layer = m_layers[i]; var includePaddedSquared = include.Radius + layer.AsteroidSpacing * 2; includePaddedSquared *= includePaddedSquared; var excludePaddedSquared = exclude.HasValue ? exclude.Value.Radius - layer.AsteroidSpacing * 2 : 0; excludePaddedSquared *= excludePaddedSquared; var minPos = Vector3I.Floor(minLocal / layer.AsteroidSpacing); var maxPos = Vector3I.Ceiling(maxLocal / layer.AsteroidSpacing); for (var itr = new Vector3I_RangeIterator(ref minPos, ref maxPos); itr.IsValid(); itr.MoveNext()) { var seed = new Vector4I(itr.Current.X, itr.Current.Y, itr.Current.Z, i); var localPos = ((Vector3D)itr.Current + 0.5) * layer.AsteroidSpacing; // Very quick, include/exclude. if (Vector3D.DistanceSquared(root, localPos) > includePaddedSquared) { continue; } if (exclude.HasValue && Vector3D.DistanceSquared(excludeRoot, localPos) < excludePaddedSquared) { continue; } var localWeight = Shape.Weight(localPos) + layer.UsableRegion - 1; if (1 - layer.AsteroidDensity > localWeight) { continue; } var densityNoise = Math.Abs(m_noise.GetValue(localPos + Math.PI)) * localWeight; if (1 - layer.AsteroidDensity > densityNoise) { continue; } localPos.X += 0.45 * m_noise.GetValue(localPos) * layer.AsteroidSpacing; localPos.Y += 0.45 * m_noise.GetValue(localPos) * layer.AsteroidSpacing; localPos.Z += 0.45 * m_noise.GetValue(localPos) * layer.AsteroidSpacing; localPos.X += 0.35 * Shape.WarpSize.X * m_noiseWarp.GetValue(localPos); localPos.Y += 0.35 * Shape.WarpSize.Y * m_noiseWarp.GetValue(localPos); localPos.Z += 0.05 * Shape.WarpSize.Z * m_noiseWarp.GetValue(localPos); var worldPos = Vector3D.Transform(localPos, m_transform); ProceduralAsteroid procAst; if (!m_asteroids.TryGetValue(seed, out procAst)) { var size = m_noise.GetValue(worldPos) * (layer.AsteroidMaxSize - layer.AsteroidMinSize) + layer.AsteroidMinSize; m_asteroids[seed] = procAst = new ProceduralAsteroid(this, seed, worldPos, size, m_layers[i]); } procAst.SpawnIfNeeded((procAst.m_boundingBox.Center - include.Center).LengthSquared()); yield return(procAst); } } }