Exemple #1
0
        public XmlDocument LoadSectorXml()
        {
            var filename = Path.Combine(Savepath, SpaceEngineersConsts.SandBoxCheckpointFilename);
            var xDoc     = new XmlDocument();

            try
            {
                if (ZipTools.IsGzipedFile(filename))
                {
                    // New file format is compressed.
                    // These steps could probably be combined, but would have to use a MemoryStream, which has memory limits before it causes performance issues when chunking memory.
                    // Using a temporary file in this situation has less performance issues as it's moved straight to disk.
                    var tempFilename = TempfileUtil.NewFilename();
                    ZipTools.GZipUncompress(filename, tempFilename);
                    xDoc.Load(tempFilename);
                    _compressedCheckpointFormat = true;
                }
                else
                {
                    // Old file format is raw XML.
                    xDoc.Load(filename);
                    _compressedCheckpointFormat = false;
                }
            }
            catch
            {
                return(null);
            }

            return(xDoc);
        }
Exemple #2
0
        public void SaveSectorXml(bool backupFile, XmlDocument xDoc)
        {
            var sectorFilename = Path.Combine(Savepath, SpaceEngineersConsts.SandBoxSectorFilename);

            if (backupFile)
            {
                var sectorBackupFilename = sectorFilename + ".bak";

                if (File.Exists(sectorBackupFilename))
                {
                    FileSystem.DeleteFile(sectorBackupFilename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                }

                File.Move(sectorFilename, sectorBackupFilename);
            }

            if (_compressedSectorFormat)
            {
                var tempFilename = TempfileUtil.NewFilename();
                xDoc.Save(tempFilename);
                ZipTools.GZipCompress(tempFilename, sectorFilename);
            }
            else
            {
                xDoc.Save(sectorFilename);
            }
        }
Exemple #3
0
        public void SaveCheckPoint(bool backupFile)
        {
            var checkpointFilename = Path.Combine(Savepath, SpaceEngineersConsts.SandBoxCheckpointFilename);

            if (backupFile)
            {
                var checkpointBackupFilename = checkpointFilename + ".bak";

                if (File.Exists(checkpointBackupFilename))
                {
                    FileSystem.DeleteFile(checkpointBackupFilename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                }

                File.Move(checkpointFilename, checkpointBackupFilename);
            }

            if (_compressedCheckpointFormat)
            {
                var tempFilename = TempfileUtil.NewFilename();
                SpaceEngineersApi.WriteSpaceEngineersFile(Checkpoint, tempFilename);
                ZipTools.GZipCompress(tempFilename, checkpointFilename);
            }
            else
            {
                SpaceEngineersApi.WriteSpaceEngineersFile(Checkpoint, checkpointFilename);
            }
        }
        public void ReseedExecuted()
        {
            MainViewModel.IsBusy = true;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true);

            var cellCount = asteroid.SumVoxelCells();

            // TODO: regenerate the materials inside of the asteroid randomly.


            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);
            DataModel.SourceVoxelFilepath = tempfilename;

            MainViewModel.IsModified = true;
            MainViewModel.IsBusy     = false;

            DataModel.MaterialAssets = null;
            DataModel.InitializeAsync();
        }
        public void ReseedExecuted()
        {
            MainViewModel.IsBusy = true;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile);

            var cellCount = asteroid.VoxCells;

            // TODO: regenerate the materials inside of the asteroid randomly.


            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);
            DataModel.UpdateNewSource(asteroid, tempfilename);

            MainViewModel.IsModified = true;
            MainViewModel.IsBusy     = false;

            DataModel.MaterialAssets = null;
            DataModel.InitializeAsync();
        }
        public string GetDataPathOrDefault(string key, string defaultValue)
        {
            if (key != null && _contentDataPaths.ContainsKey(key.ToLower()))
            {
                if (_contentDataPaths[key.ToLower()].AbsolutePath != null)
                {
                    return(_contentDataPaths[key.ToLower()].AbsolutePath);
                }

                if (_contentDataPaths[key.ToLower()].ZipFilePath != null)
                {
                    var tempContentFile = TempfileUtil.NewFilename(Path.GetExtension(defaultValue));
                    try
                    {
                        ZipTools.ExtractZipFileToFile(_contentDataPaths[key.ToLower()].ZipFilePath, null, _contentDataPaths[key.ToLower()].ReferencePath, tempContentFile);
                        return(tempContentFile);
                    }
                    catch (Exception ex)
                    {
                        // ignore errors, keep on trucking just like SE.
                        // write event log warning of any files not loaded.
                        DiagnosticsLogging.LogWarning(string.Format(Res.ExceptionState_CorruptModFile, _contentDataPaths[key.ToLower()].ZipFilePath), ex);
                        return(defaultValue);
                    }
                }
            }

            return(defaultValue);
        }
        public void ReplaceSelectedExecuted(string materialName)
        {
            MainViewModel.IsBusy = true;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true);

            if (string.IsNullOrEmpty(materialName))
            {
                asteroid.RemoveContent(SelectedMaterialAsset.MaterialName, null);
                DataModel.VoxCells = asteroid.SumVoxelCells();
            }
            else
            {
                asteroid.ReplaceMaterial(SelectedMaterialAsset.MaterialName, materialName);
            }

            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);
            DataModel.SourceVoxelFilepath = tempfilename;

            MainViewModel.IsModified = true;
            MainViewModel.IsBusy     = false;

            DataModel.UpdateGeneralFromEntityBase();
            DataModel.MaterialAssets = null;
            DataModel.InitializeAsync();
        }
Exemple #8
0
        private static bool TryReadSpaceEngineersFileXml <T>(string filename, out T outObject, out bool isCompressed, bool snapshot = false) where T : MyObjectBuilder_Base
        {
            isCompressed = false;

            if (File.Exists(filename))
            {
                var tempFilename = filename;

                if (snapshot)
                {
                    // Snapshot used for Report on Dedicated servers to prevent locking of the orginal file whilst reading it.
                    tempFilename = TempfileUtil.NewFilename();
                    File.Copy(filename, tempFilename);
                }

                using (var fileStream = new FileStream(tempFilename, FileMode.Open, FileAccess.Read))
                {
                    var b1 = fileStream.ReadByte();
                    var b2 = fileStream.ReadByte();
                    isCompressed = (b1 == 0x1f && b2 == 0x8b);
                }

                return(MyObjectBuilderSerializer.DeserializeXML <T>(tempFilename, out outObject));
            }

            outObject = null;
            return(false);
        }
Exemple #9
0
        public static bool TryReadSpaceEngineersFile <T>(string filename, out T outObject, out bool isCompressed, bool snapshot = false) where T : MyObjectBuilder_Base
        {
            string protoBufFile = filename + SpaceEngineersConsts.ProtobuffersExtension;

            if (File.Exists(protoBufFile))
            {
                var tempFilename = protoBufFile;

                if (snapshot)
                {
                    // Snapshot used for Report on Dedicated servers to prevent locking of the orginal file whilst reading it.
                    tempFilename = TempfileUtil.NewFilename();
                    File.Copy(protoBufFile, tempFilename);
                }

                using (var fileStream = new FileStream(tempFilename, FileMode.Open, FileAccess.Read))
                {
                    var b1 = fileStream.ReadByte();
                    var b2 = fileStream.ReadByte();
                    isCompressed = (b1 == 0x1f && b2 == 0x8b);
                }

                bool retCode = MyObjectBuilderSerializer.DeserializePB <T>(tempFilename, out outObject);
                if (retCode && outObject != null)
                {
                    return(true);
                }
                return(TryReadSpaceEngineersFileXml(filename, out outObject, out isCompressed, snapshot));
            }

            return(TryReadSpaceEngineersFileXml(filename, out outObject, out isCompressed, snapshot));
        }
Exemple #10
0
        public string SaveTemporarySandbox()
        {
            IsBusy = true;

            var tempFilename = TempfileUtil.NewFilename(".xml");

            SpaceEngineersApi.WriteSpaceEngineersFile <MyObjectBuilder_Sector>(ActiveWorld.SectorData, tempFilename);

            IsBusy = false;
            return(tempFilename);
        }
Exemple #11
0
        public void GenerateTempFiles()
        {
            for (var i = 0; i < 10; i++)
            {
                var file1 = TempfileUtil.NewFilename(null);
                File.WriteAllBytes(file1, new byte[] { 0x00, 0x01, 0x02 });

                var file2 = TempfileUtil.NewFilename(".txt");
                File.WriteAllText(file2, "blah blah");
            }

            TempfileUtil.Dispose();
        }
        private MyObjectBuilder_VoxelMap BuildAsteroidEntity()
        {
            var filenamepart = Path.GetFileNameWithoutExtension(Filename);
            var filename     = MainViewModel.CreateUniqueVoxelStorageName(filenamepart + MyVoxelMap.V2FileExtension);

            Position = Position.RoundOff(1.0);
            Forward  = Forward.RoundToAxis();
            Up       = Up.RoundToAxis();

            var entity = new MyObjectBuilder_VoxelMap(Position.ToVector3(), filename)
            {
                EntityId        = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID),
                PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene,
                StorageName     = Path.GetFileNameWithoutExtension(filename)
            };

            double multiplier;

            if (IsMultipleScale)
            {
                multiplier = MultipleScale;
            }
            else
            {
                multiplier = MaxLengthScale / Math.Max(Math.Max(OriginalModelSize.Height, OriginalModelSize.Width), OriginalModelSize.Depth);
            }

            var transform = MeshHelper.TransformVector(new Vector3D(0, 0, 0), 0, 0, 0);

            SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            var baseMaterial = SpaceEngineersCore.Resources.VoxelMaterialDefinitions.FirstOrDefault(m => m.IsRare == false) ?? SpaceEngineersCore.Resources.VoxelMaterialDefinitions.FirstOrDefault();

            var voxelMap = MyVoxelBuilder.BuildAsteroidFromModel(true, Filename, OutsideStockMaterial.MaterialIndex.Value, baseMaterial.Index, InsideStockMaterial.Value != null, InsideStockMaterial.MaterialIndex, ModelTraceVoxel.ThinSmoothed, multiplier, transform, MainViewModel.ResetProgress, MainViewModel.IncrementProgress);

            voxelMap.Save(SourceFile);

            MainViewModel.ClearProgress();

            entity.PositionAndOrientation = new MyPositionAndOrientation
            {
                Position = Position.ToVector3D(),
                Forward  = Forward.ToVector3(),
                Up       = Up.ToVector3()
            };

            IsValidModel = voxelMap.BoundingContent.Size.Volume() > 0;

            return(entity);
        }
        public void SliceHalfExecuted()
        {
            MainViewModel.IsBusy = true;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile);
            asteroid.RefreshAssets();

            var height = asteroid.BoundingContent.Size.Y + 1;

            // remove the Top half.
            asteroid.RemoveMaterial(null, null, (int)Math.Round(asteroid.ContentCenter.Y, 0), asteroid.Size.Y, null, null);

            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);

            var newFilename = MainViewModel.CreateUniqueVoxelStorageName(DataModel.Name);
            var posOrient   = DataModel.PositionAndOrientation.HasValue ? DataModel.PositionAndOrientation.Value : new MyPositionAndOrientation();

            posOrient.Position.y += height;

            // genreate a new Asteroid entry.
            var newEntity = new MyObjectBuilder_VoxelMap
            {
                EntityId               = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID),
                PersistentFlags        = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene,
                StorageName            = Path.GetFileNameWithoutExtension(newFilename),
                PositionAndOrientation = new MyPositionAndOrientation
                {
                    Position = posOrient.Position,
                    Forward  = posOrient.Forward,
                    Up       = posOrient.Up
                }
            };

            var structure = MainViewModel.AddEntity(newEntity);

            ((StructureVoxelModel)structure).UpdateNewSource(asteroid, tempfilename); // Set the temporary file location of the Source Voxel, as it hasn't been written yet.

            MainViewModel.IsModified = true;
            MainViewModel.IsBusy     = false;
        }
        /// <summary>
        /// Regenerate the Planet voxel.
        /// </summary>
        /// <param name="seed"></param>
        /// <param name="radius"></param>
        public void RegeneratePlanet(int seed, float radius)
        {
            MyPlanetStorageProvider     provider         = new MyPlanetStorageProvider();
            MyPlanetGeneratorDefinition planetDefinition = MyDefinitionManager.Static.GetDefinition <MyPlanetGeneratorDefinition>(MyStringHash.GetOrCompute(Planet.PlanetGenerator));

            provider.Init(seed, planetDefinition, radius);

            float minHillSize = provider.Radius * planetDefinition.HillParams.Min;
            float maxHillSize = provider.Radius * planetDefinition.HillParams.Max;

            float atmosphereRadius = planetDefinition.AtmosphereSettings.HasValue && planetDefinition.AtmosphereSettings.Value.Scale > 1f ? 1 + planetDefinition.AtmosphereSettings.Value.Scale : 1.75f;

            atmosphereRadius *= provider.Radius;

            Planet.Seed                 = seed;
            Planet.Radius               = radius;
            Planet.AtmosphereRadius     = atmosphereRadius;
            Planet.MinimumSurfaceRadius = radius + minHillSize;
            Planet.MaximumHillRadius    = radius + maxHillSize;

            provider.Init(Planet.Seed, planetDefinition, radius);

            var asteroid = new MyVoxelMap();

            asteroid.Storage = new MyOctreeStorage(provider, provider.StorageSize);
            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);
            //SourceVoxelFilepath = tempfilename;
            UpdateNewSource(asteroid, tempfilename);

            RaisePropertyChanged(() => Seed);
            RaisePropertyChanged(() => Radius);
            RaisePropertyChanged(() => AtmosphereRadius);
            RaisePropertyChanged(() => MinimumSurfaceRadius);
            RaisePropertyChanged(() => MaximumHillRadius);

            //Size = _voxelMap.Size;
            //_contentCenter = _voxelMap.ContentCenter;
            //IsValid = _voxelMap.IsValid;
            //RaisePropertyChanged(() => Size);
            //RaisePropertyChanged(() => IsValid);
            //Center = new Vector3D(_contentCenter.X + 0.5f + PositionX, _contentCenter.Y + 0.5f + PositionY, _contentCenter.Z + 0.5f + PositionZ);
            //WorldAABB = new BoundingBoxD(PositionAndOrientation.Value.Position, PositionAndOrientation.Value.Position + new Vector3D(Size));
        }
        public void RotateAsteroid(VRageMath.Quaternion quaternion)
        {
            var sourceFile = SourceVoxelFilepath ?? VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true);

            var newAsteroid = new MyVoxelMap();
            var transSize   = Vector3I.Transform(asteroid.Size, quaternion);
            var newSize     = Vector3I.Abs(transSize);

            newAsteroid.Init(Vector3D.Zero, newSize, SpaceEngineersCore.Resources.GetDefaultMaterialName());

            Vector3I coords;

            for (coords.Z = 0; coords.Z < asteroid.Size.Z; coords.Z++)
            {
                for (coords.Y = 0; coords.Y < asteroid.Size.Y; coords.Y++)
                {
                    for (coords.X = 0; coords.X < asteroid.Size.X; coords.X++)
                    {
                        byte   volume = 0xff;
                        string cellMaterial;

                        asteroid.GetVoxelMaterialContent(ref coords, out cellMaterial, out volume);

                        var newCoord = Vector3I.Transform(coords, quaternion);
                        // readjust the points, as rotation occurs arround 0,0,0.
                        newCoord.X = newCoord.X < 0 ? newCoord.X - transSize.X : newCoord.X;
                        newCoord.Y = newCoord.Y < 0 ? newCoord.Y - transSize.Y : newCoord.Y;
                        newCoord.Z = newCoord.Z < 0 ? newCoord.Z - transSize.Z : newCoord.Z;
                        newAsteroid.SetVoxelContent(volume, ref newCoord);
                        newAsteroid.SetVoxelMaterialAndIndestructibleContent(cellMaterial, 0xff, ref newCoord);
                    }
                }
            }

            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            newAsteroid.Save(tempfilename);

            SourceVoxelFilepath = tempfilename;
        }
Exemple #16
0
        public void SaveSector(bool backupFile)
        {
            var sectorFilename = Path.Combine(Savepath, SpaceEngineersConsts.SandBoxSectorFilename);

            if (backupFile)
            {
                // xml sector file.  (it may or may not be compressed)
                var sectorBackupFilename = sectorFilename + ".bak";

                if (File.Exists(sectorBackupFilename))
                {
                    FileSystem.DeleteFile(sectorBackupFilename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                }

                File.Move(sectorFilename, sectorBackupFilename);

                // binary sector file. (it may or may not be compressed)
                sectorBackupFilename = sectorFilename + SpaceEngineersConsts.ProtobuffersExtension + ".bak";

                if (File.Exists(sectorBackupFilename))
                {
                    FileSystem.DeleteFile(sectorBackupFilename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                }

                // The protoBuf .sbsPB may not exist in older save games.
                if (File.Exists(sectorFilename + SpaceEngineersConsts.ProtobuffersExtension))
                {
                    File.Move(sectorFilename + SpaceEngineersConsts.ProtobuffersExtension, sectorBackupFilename);
                }
            }

            if (_compressedSectorFormat)
            {
                var tempFilename = TempfileUtil.NewFilename();
                SpaceEngineersApi.WriteSpaceEngineersFile(SectorData, tempFilename);
                ZipTools.GZipCompress(tempFilename, sectorFilename);
            }
            else
            {
                SpaceEngineersApi.WriteSpaceEngineersFile(SectorData, sectorFilename);
            }
            SpaceEngineersApi.WriteSpaceEngineersFilePB(SectorData, sectorFilename + SpaceEngineersConsts.ProtobuffersExtension, _compressedSectorFormat);
        }
        public void ReplaceSurfaceExecuted(string materialName)
        {
            MainViewModel.IsBusy = true;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true);

            asteroid.ForceShellMaterial(materialName, 2);

            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);
            DataModel.SourceVoxelFilepath = tempfilename;

            MainViewModel.IsModified = true;
            MainViewModel.IsBusy     = false;

            DataModel.MaterialAssets = null;
            DataModel.InitializeAsync();
        }
        public void ReplaceAllExecuted(string materialName)
        {
            MainViewModel.IsBusy = true;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile);

            asteroid.ForceBaseMaterial(materialName, materialName);

            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            asteroid.Save(tempfilename);
            DataModel.UpdateNewSource(asteroid, tempfilename);

            MainViewModel.IsModified = true;
            MainViewModel.IsBusy     = false;

            DataModel.MaterialAssets = null;
            DataModel.InitializeAsync();
        }
        public MyObjectBuilder_EntityBase BuildEntity()
        {
            var asteroidCenter = new VRageMath.Vector3D();
            var asteroidSize   = new Vector3I();

            string originalFile = null;

            if (IsStockVoxel)
            {
                var stockfile = StockVoxel.SourceFilename;

                if (StockMaterial == null || StockMaterial.Value == null)
                {
                    SourceFile   = stockfile;
                    originalFile = SourceFile;
                    var asteroid = new MyVoxelMap();
                    asteroid.Load(stockfile);
                    asteroidCenter = asteroid.BoundingContent.Center;
                    asteroidSize   = asteroid.BoundingContent.Size + 1; // Content size
                }
                else
                {
                    var asteroid = new MyVoxelMap();
                    asteroid.Load(stockfile);
                    asteroid.ForceBaseMaterial(SpaceEngineersCore.Resources.GetDefaultMaterialName(), StockMaterial.Value);
                    SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);
                    asteroid.Save(SourceFile);

                    originalFile   = StockVoxel.SourceFilename;
                    asteroidCenter = asteroid.BoundingContent.Center;
                    asteroidSize   = asteroid.BoundingContent.Size + 1; // Content size
                }
            }
            else if (IsFileVoxel)
            {
                originalFile = SourceFile;

                var asteroid = new MyVoxelMap();
                asteroid.Load(SourceFile);
                asteroidCenter = asteroid.BoundingContent.Center;
                asteroidSize   = asteroid.BoundingContent.Size + 1; // Content size

                if (StockMaterial != null && StockMaterial.Value != null)
                {
                    asteroid.ForceBaseMaterial(SpaceEngineersCore.Resources.GetDefaultMaterialName(), StockMaterial.Value);
                    SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);
                    asteroid.Save(SourceFile);
                }
            }
            else if (IsSphere)
            {
                byte materialIndex;
                if (StockMaterial?.MaterialIndex != null)
                {
                    materialIndex = StockMaterial.MaterialIndex.Value;
                }
                else
                {
                    materialIndex = SpaceEngineersCore.Resources.GetDefaultMaterialIndex();
                }

                string materialName = SpaceEngineersCore.Resources.GetMaterialName(materialIndex);

                originalFile = string.Format("sphere_{0}_{1}_{2}{3}", materialName.ToLowerInvariant(), SphereRadius, SphereShellRadius, MyVoxelMap.V2FileExtension);

                var asteroid = MyVoxelBuilder.BuildAsteroidSphere(SphereRadius > 32, SphereRadius, materialIndex, materialIndex, SphereShellRadius != 0, SphereShellRadius);
                // TODO: progress bar.
                asteroidCenter = asteroid.BoundingContent.Center;
                asteroidSize   = asteroid.BoundingContent.Size + 1; // Content size
                SourceFile     = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);
                asteroid.Save(SourceFile);
            }

            // automatically number all files, and check for duplicate filenames.
            Filename = MainViewModel.CreateUniqueVoxelStorageName(originalFile);

            // Figure out where the Character is facing, and plant the new constrcut right in front.
            // Calculate the hypotenuse, as it will be the safest distance to place in front.
            double distance = Math.Sqrt(Math.Pow(asteroidSize.X, 2) + Math.Pow(asteroidSize.Y, 2) + Math.Pow(asteroidSize.Z, 2)) / 2;

            var vector = new BindableVector3DModel(_dataModel.CharacterPosition.Forward).Vector3D;

            vector.Normalize();
            vector   = System.Windows.Media.Media3D.Vector3D.Multiply(vector, distance);
            Position = new BindablePoint3DModel(Point3D.Add(new BindablePoint3DModel(_dataModel.CharacterPosition.Position).Point3D, vector));
            //Forward = new BindableVector3DModel(_dataModel.CharacterPosition.Forward);
            //Up = new BindableVector3DModel(_dataModel.CharacterPosition.Up);
            Forward = new BindableVector3DModel(Vector3.Forward);  // Asteroids currently don't have any orientation.
            Up      = new BindableVector3DModel(Vector3.Up);

            var entity = new MyObjectBuilder_VoxelMap
            {
                EntityId               = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID),
                PersistentFlags        = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene,
                StorageName            = Path.GetFileNameWithoutExtension(Filename),
                PositionAndOrientation = new MyPositionAndOrientation
                {
                    Position = Position.ToVector3D() - asteroidCenter,
                    Forward  = Forward.ToVector3(),
                    Up       = Up.ToVector3()
                }
            };

            return(entity);
        }
        private bool ExtractStationIntersect(bool tightIntersection)
        {
            // Make a shortlist of station Entities in the bounding box of the asteroid.
            var asteroidWorldAABB = new BoundingBoxD(DataModel.ContentBounds.Min + DataModel.PositionAndOrientation.Value.Position, DataModel.ContentBounds.Max + DataModel.PositionAndOrientation.Value.Position);
            var stations          = MainViewModel.GetIntersectingEntities(asteroidWorldAABB).Where(e => e.ClassType == ClassType.Station).Cast <StructureCubeGridModel>().ToList();

            if (stations.Count == 0)
            {
                return(false);
            }

            var modified   = false;
            var sourceFile = DataModel.SourceVoxelFilepath ?? DataModel.VoxelFilepath;
            var asteroid   = new MyVoxelMap();

            asteroid.Load(sourceFile, SpaceEngineersCore.Resources.GetDefaultMaterialName(), true);

            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))
                    {
                        var pointMin = new Vector3I(cubeWorldAABB.Min - DataModel.PositionAndOrientation.Value.Position);
                        var pointMax = new Vector3I(cubeWorldAABB.Max - DataModel.PositionAndOrientation.Value.Position);

                        Vector3I coords;
                        for (coords.Z = pointMin.Z; coords.Z <= pointMax.Z; coords.Z++)
                        {
                            for (coords.Y = pointMin.Y; coords.Y <= pointMax.Y; coords.Y++)
                            {
                                for (coords.X = pointMin.X; coords.X <= pointMax.X; coords.X++)
                                {
                                    if (coords.X >= 0 && coords.Y >= 0 && coords.Z >= 0 && coords.X < asteroid.Size.X && coords.Y < asteroid.Size.Y && coords.Z < asteroid.Size.Z)
                                    {
                                        asteroid.SetVoxelContent(0, ref coords);
                                    }
                                }
                            }
                        }

                        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.
                DataModel.SourceVoxelFilepath = tempfilename;
            }
            return(modified);
        }
        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);
        }
        private bool BuildEntity()
        {
            var filenamepart = Path.GetFileNameWithoutExtension(Filename);
            var filename     = MainViewModel.CreateUniqueVoxelStorageName(filenamepart + MyVoxelMap.V2FileExtension);

            double multiplier;

            if (IsMultipleScale)
            {
                multiplier = MultipleScale;
            }
            else
            {
                multiplier = MaxLengthScale / Math.Max(Math.Max(OriginalModelSize.Height, OriginalModelSize.Width), OriginalModelSize.Depth);
            }

            var scale           = new ScaleTransform3D(multiplier, multiplier, multiplier);
            var rotateTransform = MeshHelper.TransformVector(new System.Windows.Media.Media3D.Vector3D(0, 0, 0), -RotateRoll, RotateYaw - 90, RotatePitch + 90);

            SourceFile = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            var model = MeshHelper.Load(Filename, ignoreErrors: true);

            var meshes      = new List <MyVoxelRayTracer.MyMeshModel>();
            var geometeries = new List <MeshGeometry3D>();

            foreach (var model3D in model.Children)
            {
                var gm       = (GeometryModel3D)model3D;
                var geometry = gm.Geometry as MeshGeometry3D;

                if (geometry != null)
                {
                    geometeries.Add(geometry);
                }
            }
            meshes.Add(new MyVoxelRayTracer.MyMeshModel(geometeries.ToArray(), InsideStockMaterial.MaterialIndex, InsideStockMaterial.MaterialIndex));

            #region handle dialogs and process the conversion

            var doCancel = false;

            var progressModel = new ProgressCancelModel {
                Title = Res.WnProgressTitle, SubTitle = Res.WnProgressTitle, DialogText = Res.WnProgressTxtTimeRemain + " " + Res.WnProgressTxtTimeCalculating
            };
            var progressVm = new ProgressCancelViewModel(this, progressModel);
            progressVm.CloseRequested += delegate(object sender, EventArgs e)
            {
                doCancel = true;
            };

            var cancelFunc = (Func <bool>) delegate
            {
                return(doCancel);
            };

            var completedAction = (Action) delegate
            {
                progressVm.Close();
            };

            MyVoxelMap voxelMap = null;

            var action = (Action) delegate
            {
                voxelMap = MyVoxelRayTracer.ReadModelAsteroidVolmetic(model, meshes, scale, rotateTransform, TraceType, TraceCount, TraceDirection,
                                                                      progressModel.ResetProgress, progressModel.IncrementProgress, cancelFunc, completedAction);
            };

            if (RunInLowPrioity)
            {
                System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.Idle;
            }

            _dialogService.ShowDialog <WindowProgressCancel>(this, progressVm, action);

            if (RunInLowPrioity)
            {
                System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.Normal;
            }

            #endregion

            if (doCancel || voxelMap == null)
            {
                IsValidEntity = false;
                NewEntity     = null;
            }
            else
            {
                voxelMap.ForceShellMaterial(OutsideStockMaterial.Value, (byte)OutsideMaterialDepth);
                voxelMap.Save(SourceFile);

                var position = VRageMath.Vector3D.Zero;
                var forward  = Vector3.Forward;
                var up       = Vector3.Up;

                if (IsAbsolutePosition)
                {
                    position = Position.ToVector3();
                }
                else if (IsInfrontofPlayer)
                {
                    // Figure out where the Character is facing, and plant the new construct centered in front of the Character, but "BuildDistance" units out in front.
                    var lookVector = (VRageMath.Vector3D)_dataModel.CharacterPosition.Forward.ToVector3();
                    lookVector.Normalize();

                    BoundingBoxD       content = voxelMap.BoundingContent.ToBoundingBoxD();
                    VRageMath.Vector3D?boundingIntersectPoint = content.IntersectsRayAt(content.Center, -lookVector * 5000d);

                    if (!boundingIntersectPoint.HasValue)
                    {
                        boundingIntersectPoint = content.Center;
                    }

                    var distance = VRageMath.Vector3D.Distance(boundingIntersectPoint.Value, content.Center) + (float)BuildDistance;
                    VRageMath.Vector3D vector = lookVector * distance;
                    position = VRageMath.Vector3D.Add(_dataModel.CharacterPosition.Position, vector) - content.Center;
                }

                var entity = new MyObjectBuilder_VoxelMap(position, filename)
                {
                    EntityId        = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID),
                    PersistentFlags = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene,
                    StorageName     = Path.GetFileNameWithoutExtension(filename)
                };

                entity.PositionAndOrientation = new MyPositionAndOrientation
                {
                    Position = position,
                    Forward  = forward,
                    Up       = up
                };

                IsValidEntity = voxelMap.BoundingContent.Size.Volume() > 0;

                NewEntity = entity;

                if (BeepWhenFinished)
                {
                    System.Media.SystemSounds.Asterisk.Play();
                }
            }

            return(!doCancel);
        }
        public MyObjectBuilder_EntityBase BuildEntity()
        {
            // Realign both asteroids to a common grid, so voxels can be lined up.
            Vector3I roundedPosLeft  = SelectionLeft.WorldAABB.Min.RoundToVector3I();
            Vector3D offsetPosLeft   = SelectionLeft.WorldAABB.Min - (Vector3D)roundedPosLeft;   // Use for everything.
            Vector3I roundedPosRight = (SelectionRight.WorldAABB.Min - offsetPosLeft).RoundToVector3I();
            Vector3D offsetPosRight  = SelectionRight.WorldAABB.Min - (Vector3D)roundedPosRight; // Use for everything.

            // calculate smallest allowable size for contents of both.
            const int paddCells = 3;

            // Force a calculation of the ContentBounds, as multi select in the ListView doesn't necessarily make it happen, or make it happen fast enough.
            SelectionLeft.LoadDetailsSync();
            SelectionRight.LoadDetailsSync();

            var minLeft      = SelectionLeft.WorldAABB.Min + SelectionLeft.InflatedContentBounds.Min - offsetPosLeft;
            var minRight     = SelectionRight.WorldAABB.Min + SelectionRight.InflatedContentBounds.Min - offsetPosRight;
            var min          = Vector3D.Zero;
            var posOffset    = Vector3D.Zero;
            var asteroidSize = Vector3I.Zero;

            switch (VoxelMergeType)
            {
            case VoxelMergeType.UnionVolumeLeftToRight:
            case VoxelMergeType.UnionVolumeRightToLeft:
                min = Vector3D.Min(minLeft, minRight) - paddCells;
                var max = Vector3D.Max(SelectionLeft.WorldAABB.Min + SelectionLeft.InflatedContentBounds.Max - offsetPosLeft, SelectionRight.WorldAABB.Min + SelectionRight.InflatedContentBounds.Max - offsetPosRight) + paddCells;
                posOffset = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z);
                var size = (max - min).RoundToVector3I();
                asteroidSize = MyVoxelBuilder.CalcRequiredSize(size);
                break;

            case VoxelMergeType.UnionMaterialLeftToRight:
                min          = SelectionRight.WorldAABB.Min - offsetPosRight;
                posOffset    = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z);
                asteroidSize = SelectionRight.Size;
                break;

            case VoxelMergeType.UnionMaterialRightToLeft:
                min          = SelectionLeft.WorldAABB.Min - offsetPosLeft;
                posOffset    = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z);
                asteroidSize = SelectionLeft.Size;
                break;

            case VoxelMergeType.SubtractVolumeLeftFromRight:
                min          = SelectionRight.WorldAABB.Min - offsetPosRight;
                posOffset    = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z);
                asteroidSize = SelectionRight.Size;
                break;

            case VoxelMergeType.SubtractVolumeRightFromLeft:
                min          = SelectionLeft.WorldAABB.Min - offsetPosLeft;
                posOffset    = new Vector3D(minLeft.X < minRight.X ? offsetPosLeft.X : offsetPosRight.X, minLeft.Y < minRight.Y ? offsetPosLeft.Y : offsetPosRight.Y, minLeft.Z < minRight.Z ? offsetPosLeft.Z : offsetPosRight.Z);
                asteroidSize = SelectionLeft.Size;
                break;
            }

            // Prepare new asteroid.
            var newAsteroid = new MyVoxelMap();

            newAsteroid.Create(asteroidSize, SpaceEngineersCore.Resources.GetDefaultMaterialIndex());
            if (string.IsNullOrEmpty(MergeFileName))
            {
                MergeFileName = "merge";
            }
            var filename = MainViewModel.CreateUniqueVoxelStorageName(MergeFileName);

            // merge.
            switch (VoxelMergeType)
            {
            case VoxelMergeType.UnionVolumeLeftToRight:
                MergeAsteroidVolumeInto(ref newAsteroid, min, SelectionRight, SelectionLeft, minRight, minLeft);
                break;

            case VoxelMergeType.UnionVolumeRightToLeft:
                MergeAsteroidVolumeInto(ref newAsteroid, min, SelectionLeft, SelectionRight, minLeft, minRight);
                break;

            case VoxelMergeType.UnionMaterialLeftToRight:
                MergeAsteroidMaterialFrom(ref newAsteroid, min, SelectionRight, SelectionLeft, minRight, minLeft);
                break;

            case VoxelMergeType.UnionMaterialRightToLeft:
                MergeAsteroidMaterialFrom(ref newAsteroid, min, SelectionLeft, SelectionRight, minLeft, minRight);
                break;

            case VoxelMergeType.SubtractVolumeLeftFromRight:
                SubtractAsteroidVolumeFrom(ref newAsteroid, min, SelectionRight, SelectionLeft, minRight, minLeft);
                break;

            case VoxelMergeType.SubtractVolumeRightFromLeft:
                SubtractAsteroidVolumeFrom(ref newAsteroid, min, SelectionLeft, SelectionRight, minLeft, minRight);
                break;
            }

            // Generate Entity
            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);

            newAsteroid.Save(tempfilename);
            SourceFile = tempfilename;

            var position = min + posOffset;
            var entity   = new MyObjectBuilder_VoxelMap(position, filename)
            {
                EntityId               = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID),
                PersistentFlags        = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene,
                StorageName            = Path.GetFileNameWithoutExtension(filename),
                PositionAndOrientation = new MyPositionAndOrientation
                {
                    Position = position,
                    Forward  = Vector3.Forward,
                    Up       = Vector3.Up
                }
            };

            return(entity);
        }
        /// <returns>True if it sucessfully deserialized the file.</returns>
        public static bool TryReadSpaceEngineersFile <T>(string filename, out T outObject, out bool isCompressed, out string errorInformation, bool snapshot = false, bool specificExtension = false) where T : MyObjectBuilder_Base
        {
            string protoBufFile = null;

            if (specificExtension)
            {
                if ((Path.GetExtension(filename) ?? string.Empty).EndsWith(SpaceEngineersConsts.ProtobuffersExtension, StringComparison.OrdinalIgnoreCase))
                {
                    protoBufFile = filename;
                }
            }
            else
            {
                if ((Path.GetExtension(filename) ?? string.Empty).EndsWith(SpaceEngineersConsts.ProtobuffersExtension, StringComparison.OrdinalIgnoreCase))
                {
                    protoBufFile = filename;
                }
                else
                {
                    protoBufFile = filename + SpaceEngineersConsts.ProtobuffersExtension;
                }
            }

            if (protoBufFile != null && File.Exists(protoBufFile))
            {
                var tempFilename = protoBufFile;

                if (snapshot)
                {
                    // Snapshot used for Report on Dedicated servers to prevent locking of the orginal file whilst reading it.
                    tempFilename = TempfileUtil.NewFilename();
                    File.Copy(protoBufFile, tempFilename);
                }

                using (var fileStream = new FileStream(tempFilename, FileMode.Open, FileAccess.Read))
                {
                    var b1 = fileStream.ReadByte();
                    var b2 = fileStream.ReadByte();
                    isCompressed = (b1 == 0x1f && b2 == 0x8b);
                }

                bool retCode;
                try
                {
                    // A failure to load here, will only mean it falls back to try and read the xml file instead.
                    // So a file corruption could easily have been covered up.
                    retCode = MyObjectBuilderSerializer.DeserializePB <T>(tempFilename, out outObject);
                }
                catch (InvalidCastException ex)
                {
                    outObject        = null;
                    errorInformation = string.Format(Res.ErrorLoadFileError, filename, ex.AllMessages());
                    return(false);
                }
                if (retCode && outObject != null)
                {
                    errorInformation = null;
                    return(true);
                }
                return(TryReadSpaceEngineersFileXml(filename, out outObject, out isCompressed, out errorInformation, snapshot));
            }

            return(TryReadSpaceEngineersFileXml(filename, out outObject, out isCompressed, out errorInformation, snapshot));
        }
        public void BuildEntities(out string[] sourceVoxelFiles, out MyObjectBuilder_EntityBase[] sourceEntities)
        {
            var entities    = new List <MyObjectBuilder_EntityBase>();
            var sourceFiles = new List <string>();

            MainViewModel.ResetProgress(0, VoxelCollection.Count);

            foreach (var voxelDesign in VoxelCollection)
            {
                MainViewModel.Progress++;
                if (string.IsNullOrEmpty(voxelDesign.VoxelFile.SourceFilename) || !MyVoxelMap.IsVoxelMapFile(voxelDesign.VoxelFile.SourceFilename))
                {
                    continue;
                }


                var    asteroid           = new MyVoxelMap();
                string tempSourcefilename = null;

                switch (AsteroidFillType)
                {
                case Support.AsteroidFillType.None:
                    asteroid.Load(voxelDesign.VoxelFile.SourceFilename, voxelDesign.MainMaterial.Value, false);
                    tempSourcefilename = voxelDesign.VoxelFile.SourceFilename;
                    break;

                case AsteroidFillType.ByteFiller:
                    asteroid.Load(voxelDesign.VoxelFile.SourceFilename, voxelDesign.MainMaterial.Value, false);
                    var filler = new AsteroidByteFiller();
                    filler.FillAsteroid(asteroid, voxelDesign);
                    tempSourcefilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);
                    asteroid.Save(tempSourcefilename);
                    break;
                }


                // automatically number all files, and check for duplicate filenames.
                var filename = MainViewModel.CreateUniqueVoxelStorageName(voxelDesign.VoxelFile.Name + MyVoxelMap.V2FileExtension, entities.ToArray());

                var radius    = RandomUtil.GetDouble(MinimumRange, MaximumRange);
                var longitude = RandomUtil.GetDouble(0, 2 * Math.PI);
                var latitude  = RandomUtil.GetDouble(-Math.PI / 2, (Math.PI / 2) + double.Epsilon);

                // Test data. Place asteroids items into a circle.
                //radius = 500;
                //longitude = Math.PI * 2 * ((double)voxelDesign.Index / VoxelCollection.Count);
                //latitude = 0;

                var x = radius * Math.Cos(latitude) * Math.Cos(longitude);
                var z = radius * Math.Cos(latitude) * Math.Sin(longitude);
                var y = radius * Math.Sin(latitude);

                var center   = new Vector3D(CenterPositionX, CenterPositionY, CenterPositionZ);
                var position = center + new Vector3D(x, y, z) - asteroid.BoundingContent.Center;
                var entity   = new MyObjectBuilder_VoxelMap(position, filename)
                {
                    EntityId               = SpaceEngineersApi.GenerateEntityId(IDType.ASTEROID),
                    PersistentFlags        = MyPersistentEntityFlags2.CastShadows | MyPersistentEntityFlags2.InScene,
                    StorageName            = Path.GetFileNameWithoutExtension(filename),
                    PositionAndOrientation = new MyPositionAndOrientation
                    {
                        Position = position,
                        Forward  = Vector3.Forward, // Asteroids currently don't have any orientation.
                        Up       = Vector3.Up
                    }
                };

                entities.Add(entity);
                sourceFiles.Add(tempSourcefilename);
            }

            sourceVoxelFiles = sourceFiles.ToArray();
            sourceEntities   = entities.ToArray();
        }
        public void RotateAsteroid(Quaternion quaternion)
        {
            var sourceFile = SourceVoxelFilepath ?? VoxelFilepath;

            var asteroid = new MyVoxelMap();

            asteroid.Load(sourceFile);

            var newAsteroid = new MyVoxelMap();
            var newSize     = asteroid.Size;

            newAsteroid.Create(newSize, SpaceEngineersCore.Resources.GetDefaultMaterialIndex());

            Vector3I block;
            var      halfSize = asteroid.Storage.Size / 2;

            // Don't use anything smaller than 64 for smaller voxels, as it trashes the cache.
            var cacheSize     = new Vector3I(64);
            var halfCacheSize = new Vector3I(32); // This should only be used for the Transform, not the cache.

            // 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)
                    {
                        #region source voxel

                        var cache = new MyStorageData();
                        cache.Resize(cacheSize);
                        // LOD1 is not detailed enough for content information on asteroids.
                        asteroid.Storage.ReadRange(cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1);

                        #endregion

                        #region target Voxel

                        // the block is a cubiod. The entire space needs to rotate, to be able to gauge where the new block position starts from.
                        var newBlockMin = Vector3I.Transform(block - halfSize, quaternion) + halfSize;
                        var newBlockMax = Vector3I.Transform(block + 64 - halfSize, quaternion) + halfSize;
                        var newBlock    = Vector3I.Min(newBlockMin, newBlockMax);

                        var newCache = new MyStorageData();
                        newCache.Resize(cacheSize);
                        newAsteroid.Storage.ReadRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, newBlock, newBlock + cacheSize - 1);

                        #endregion

                        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)
                                {
                                    byte volume       = cache.Content(ref p);
                                    byte cellMaterial = cache.Material(ref p);

                                    var newP1 = Vector3I.Transform(p - halfCacheSize, quaternion) + halfCacheSize;
                                    var newP2 = Vector3I.Transform(p + 1 - halfCacheSize, quaternion) + halfCacheSize;
                                    var newP  = Vector3I.Min(newP1, newP2);

                                    newCache.Content(ref newP, volume);
                                    newCache.Material(ref newP, cellMaterial);
                                    changed = true;
                                }
                            }
                        }

                        if (changed)
                        {
                            newAsteroid.Storage.WriteRange(newCache, MyStorageDataTypeFlags.ContentAndMaterial, newBlock, newBlock + cacheSize - 1);
                        }
                    }
                }
            }


            var tempfilename = TempfileUtil.NewFilename(MyVoxelMap.V2FileExtension);
            newAsteroid.Save(tempfilename);

            SourceVoxelFilepath = tempfilename;
        }