예제 #1
0
        /// <summary>
        /// Save the world to disk. Let the caller decide if this should be in a thread because in some situations it shouldnt (ie: when loading a newly generated world the file has to be saved first).
        /// This is only called by a standalone server or a server thread running in single player. In single player the user can also manually initiate a save in which case this will be called using a Task.
        /// </summary>
        internal static void SaveToDisk()
        {
            if (File.Exists(Settings.WorldFileTempPath))
            {
                File.Delete(Settings.WorldFileTempPath);
            }

            var fstream  = new FileStream(Settings.WorldFileTempPath, FileMode.Create);
            var gzstream = new GZipStream(fstream, CompressionMode.Compress);
            //GZipStream only applies compression during .Write, writing 2 bytes at a time ends up inflating it a lot. Adding this saves up to 99.3%
            var buffstream = new BufferedStream(gzstream, 65536);
            var chunkBytes = new byte[Chunk.SIZE_IN_BYTES];

            var worldSettings = WorldSettings.GetXmlByteArray();

            buffstream.Write(BitConverter.GetBytes(worldSettings.Length), 0, sizeof(int));
            buffstream.Write(worldSettings, 0, worldSettings.Length);             //write the length of the world config xml

            for (var x = 0; x < SizeInChunksX; x++)
            {
                for (var z = 0; z < SizeInChunksZ; z++)
                {
                    Buffer.BlockCopy(Chunks[x, z].Blocks.Array, 0, chunkBytes, 0, chunkBytes.Length);
                    //Buffer.BlockCopy(Chunks[x,z].Blocks.DiffArray, 0, chunkBytes, 0, chunkBytes.Length); 'bm: this will save a diff instead, WIP
                    buffstream.Write(chunkBytes, 0, chunkBytes.Length);
                }
            }
            buffstream.Flush();
            buffstream.Close();
            gzstream.Close();
            fstream.Close();
            buffstream.Dispose();
            gzstream.Dispose();
            fstream.Dispose();

            File.Copy(Settings.WorldFileTempPath, Settings.WorldFilePath, true);
            File.Delete(Settings.WorldFileTempPath);
        }
예제 #2
0
        /// <summary>
        /// Called from Server.Controller class only. The scenarios where we load from disk are if this is a server launching with a previously saved world
        /// or if this is a single player and the server thread is loading the previously saved world.
        /// </summary>
        internal static void LoadFromDisk()
        {
            if (Config.Mode == ModeType.JoinServer)
            {
                throw new Exception("World should not be loaded from disk when joining a server.");
            }

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var fstream  = new FileStream(Settings.WorldFilePath, FileMode.Open);
            var gzstream = new GZipStream(fstream, CompressionMode.Decompress);

            var bytesRead = 0;
            var worldSettingsSizeBytes = new byte[sizeof(int)];

            while (bytesRead < sizeof(int))
            {
                bytesRead += gzstream.Read(worldSettingsSizeBytes, bytesRead, sizeof(int) - bytesRead);                 //read the size of the world config xml
            }
            var worldSettingsBytes = new byte[BitConverter.ToInt32(worldSettingsSizeBytes, 0)];

            bytesRead = 0;
            while (bytesRead < worldSettingsBytes.Length)
            {
                bytesRead += gzstream.Read(worldSettingsBytes, bytesRead, worldSettingsBytes.Length - bytesRead);
            }
            WorldSettings.LoadSettings(worldSettingsBytes);

            var chunkTotal = SizeInChunksX * SizeInChunksZ;
            var chunkCount = 1;
            var tasks      = new Task[chunkTotal];

            for (var x = 0; x < SizeInChunksX; x++)             //loop through each chunk and load it
            {
                for (var z = 0; z < SizeInChunksZ; z++)
                {
                    if (Config.IsSinglePlayer)
                    {
                        Settings.Launcher.UpdateProgressInvokable(string.Format("Loading Chunks: {0} / {1}", chunkCount, chunkTotal), chunkCount, chunkTotal);
                    }
                    var chunkBytes = new byte[Chunk.SIZE_IN_BYTES];
                    bytesRead = 0;
                    while (bytesRead < chunkBytes.Length)
                    {
                        bytesRead += gzstream.Read(chunkBytes, bytesRead, chunkBytes.Length - bytesRead);
                    }
                    int x1 = x, z1 = z;
                    var task = Task.Factory.StartNew(() => LoadChunk(Chunks[x1, z1], chunkBytes));
                    tasks[chunkCount - 1] = task;
                    chunkCount++;
                }
            }
            Task.WaitAll(tasks);
            gzstream.Close();
            fstream.Close();

            stopwatch.Stop();
            Debug.WriteLine("World load from disk time: {0}ms", stopwatch.ElapsedMilliseconds);

            InitializeAllLightMaps();
        }