public static void Save(bool message = true, bool permitBackgroundWrite = false) { if (Saving) { return; } GameServer.Instance.Clients.Each(c => c.Flush()); WaitForWriteCompletion(); // Blocks Save until current disk flush is done. Saving = true; m_DiskWriteHandle.Reset(); if (message) { Broadcast(0x35, true, "The world is saving, please wait."); } log.Info("Save started"); var strategy = SaveStrategy.Acquire(); log.Info("Using {0} save strategy", strategy.Name.ToLowerInvariant()); var watch = Stopwatch.StartNew(); try { EventSink.InvokeWorldBeforeSave(); } catch (Exception e) { throw new Exception("World Before Save event threw an exception. Save failed!", e); } if (!Directory.Exists(MobileBasePath)) { Directory.CreateDirectory(MobileBasePath); } if (!Directory.Exists(ItemBasePath)) { Directory.CreateDirectory(ItemBasePath); } if (!Directory.Exists(GuildBasePath)) { Directory.CreateDirectory(GuildBasePath); } strategy.Save(permitBackgroundWrite); log.Info("Entities saved in {0:F2} seconds.", watch.Elapsed.TotalSeconds); try { EventSink.InvokeWorldSave(new WorldSaveEventArgs(message)); } catch (Exception e) { throw new Exception("World Save event threw an exception. Save failed!", e); } if (ManualGC) { GC.Collect(); } watch.Stop(); Saving = false; if (!permitBackgroundWrite) { NotifyDiskWriteComplete(); // Sets the DiskWriteHandle. If we allow background writes, we leave this upto the individual save strategies. } ProcessSafetyQueues(); strategy.OnFinished(); log.Info("Save done in {0:F2} seconds.", watch.Elapsed.TotalSeconds); if (message) { Broadcast(0x35, true, "World save complete. The entire process took {0:F2} seconds.", watch.Elapsed.TotalSeconds); } }