/// <summary>
        /// Saves the current data in <see cref="Clusters"/>.
        /// </summary>
        public void Save()
        {
            m_BuildableDirectory.WaitDestroyHandle();
            var river = new RiverExpanded(ServerSavedata.directory + "/" + Provider.serverID + "/Level/" +
                                          Level.info.name + "/Bases.dat");

            river.WriteInt32(m_BuildableDirectory.Buildables.Count);
            var clusters = Clusters;

            river.WriteInt32(clusters.Count);
            foreach (var cluster in clusters)
            {
                river.WriteInt32(cluster.InstanceId);
                river.WriteBoolean(cluster.IsGlobalCluster);
                river.WriteInt32(cluster.Buildables.Count);
                foreach (var build in cluster.Buildables)
                {
                    river.WriteUInt32(build.InstanceId);
                    river.WriteBoolean(build is StructureBuildable);
                }
            }

            river.CloseRiver();
        }
        private bool LoadClusters(IEnumerable <Buildable> allBuildables)
        {
            var bases = new List <BaseCluster>();

            foreach (var c in m_Clusters)
            {
                Return(c);
            }

            try
            {
                var timer = Stopwatch.StartNew();
                var river = new RiverExpanded(ServerSavedata.directory + "/" + Provider.serverID + "/Level/" +
                                              Level.info.name + "/Bases.dat");
                var allBuilds  = allBuildables.ToList();
                var structures = allBuilds.OfType <StructureBuildable>().ToDictionary(k => k.InstanceId);
                var barricades = allBuilds.OfType <BarricadeBuildable>().ToDictionary(k => k.InstanceId);

                var buildableCount = river.ReadInt32();

                if (allBuilds.Count != buildableCount)
                {
                    Logging.Write(m_Plugin,
                                  "Warning! Buildable count doesn't match saved count! Buildable save data was most likely modified or lost during server downtime. Clusters will be now rebuilt.",
                                  ConsoleColor.Yellow);
                    return(false);
                }

                var clusterCount = river.ReadInt32();
                var logRate      = Math.Floor(clusterCount * 0.085);

                Logging.Write(m_Plugin,
                              $"Loading saved clusters... 0% [0/{clusterCount}] {timer.ElapsedMilliseconds}ms",
                              ConsoleColor.Cyan);

                for (var i = 0; i < clusterCount; i++)
                {
                    var builds = new List <Buildable>();
                    // Restore of instanceId is needed to maintain something unique to each cluster across restarts.
                    var instanceId = river.ReadInt32();
                    var global     = river.ReadBoolean();

                    var buildCount = river.ReadInt32();
                    for (var o = 0; o < buildCount; o++)
                    {
                        var buildInstanceId = river.ReadUInt32();
                        var isStructure     = river.ReadBoolean();
                        var build           = isStructure
                            ? (Buildable)structures[buildInstanceId]
                            : barricades[buildInstanceId];

                        if (build == null)
                        {
                            Logging.Write(m_Plugin,
                                          $"Warning! Buildable with InstanceId {buildInstanceId} [isStructure: {isStructure}] not found! Save data was most likely modified or lost during server downtime. Clusters will be now rebuilt.",
                                          ConsoleColor.Yellow);
                            river.CloseRiver();
                            return(false);
                        }

                        builds.Add(build);
                    }

                    if (global)
                    {
                        if (m_GlobalCluster != null)
                        {
                            m_GlobalCluster.AddBuildables(builds);
                        }
                        else
                        {
                            var cluster = CreateCluster(instanceId, true);
                            cluster.AddBuildables(builds);
                            m_GlobalCluster = cluster;
                        }
                    }
                    else
                    {
                        var cluster = GetOrCreatePooledCluster();
                        cluster.AddBuildables(builds);
                        bases.Add(cluster);
                    }

                    if ((i + 1) % logRate == 0)
                    {
                        Logging.Write(m_Plugin,
                                      $"Loading saved clusters... {Math.Ceiling((i + 1) / (double) clusterCount * 100)}% [{i + 1}/{clusterCount}] {timer.ElapsedMilliseconds}ms",
                                      ConsoleColor.Cyan);
                    }
                }

                m_Clusters.AddRange(bases);

                if (Clusters.Count > 0)
                {
                    m_InstanceIds = Clusters.Max(k => k.InstanceId) + 1;
                }

                for (var i = 0; i < m_InstanceIds; i++)
                {
                    if (Clusters.Any(k => k.InstanceId == i) || m_ClusterPool.Any(k => k.InstanceId == i))
                    {
                        continue;
                    }

                    m_ClusterPool.Add(CreateCluster(i));
                }

                timer.Stop();
                return(true);
            }
            catch (Exception ex)
            {
                Logging.Write(m_Plugin,
                              $"Warning! An exception was thrown when attempting to load the save file. Assuming the data is corrupted. Clusters will be now rebuilt. Exception: {ex}",
                              ConsoleColor.Yellow);

                foreach (var b in bases)
                {
                    Return(b);
                }

                return(false);
            }
        }