Exemple #1
0
        /// <summary>
        ///     Coroutine to send a package to a list of peers. Compresses and fragments the package if necessary.
        /// </summary>
        /// <param name="peers"></param>
        /// <param name="package"></param>
        /// <returns></returns>
        public IEnumerator SendPackageRoutine(List <ZNetPeer> peers, ZPackage package)
        {
            if (!ZNet.instance)
            {
                yield break;
            }

            if (peers.Count == 0)
            {
                yield break;
            }

            try
            {
                ++SendCount;

                byte[]   originalData  = package.GetArray();
                ZPackage jotunnpackage = new ZPackage();
                jotunnpackage.Write(JOTUNN_PACKAGE);
                jotunnpackage.Write(originalData);
                package = jotunnpackage;

                const int compressMinSize = 10000;

                if (package.Size() > compressMinSize)
                {
                    byte[] rawData = package.GetArray();
                    Logger.LogDebug($"[{ID}] Compressing package with length {rawData.Length}");

                    ZPackage compressedPackage = new ZPackage();
                    compressedPackage.Write(COMPRESSED_PACKAGE);
                    MemoryStream output = new MemoryStream();
                    using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal))
                    {
                        deflateStream.Write(rawData, 0, rawData.Length);
                    }

                    compressedPackage.Write(output.ToArray());
                    package = compressedPackage;
                }

                List <IEnumerator <bool> > writers =
                    peers.Where(peer => peer.IsReady()).Select(p => SendToPeer(p, package)).ToList();
                writers.RemoveAll(writer => !writer.MoveNext());
                while (writers.Count > 0)
                {
                    yield return(null);

                    writers.RemoveAll(writer => !writer.MoveNext());
                }
            }
            finally
            {
                --SendCount;
            }
        }
Exemple #2
0
        /// <summary>
        ///     Coroutine to send a package to a single target. Compresses and fragments the package if necessary.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="package"></param>
        /// <returns></returns>
        public IEnumerator SendPackageRoutine(long target, ZPackage package)
        {
            if (!ZNet.instance)
            {
                return(Enumerable.Empty <object>().GetEnumerator());
            }

            List <ZNetPeer> peers = ZRoutedRpc.instance.m_peers;

            if (target == ZRoutedRpc.instance.m_id || target == ZRoutedRpc.Everybody)
            {
                byte[]   originalData  = package.GetArray();
                ZPackage jotunnpackage = new ZPackage();
                jotunnpackage.Write(originalData);
                jotunnpackage.SetPos(0);
                ZNet.instance.StartCoroutine(
                    HandlePackageRoutine(ZRoutedRpc.instance.m_id, jotunnpackage, JOTUNN_PACKAGE));
            }
            else
            {
                peers = peers.Where(p => p.m_uid == target).ToList();
            }

            return(SendPackageRoutine(peers, package));
        }
Exemple #3
0
        private static void RPC_ShareExploration(long sender, ZPackage z)
        {
            Plugin.logger.LogDebug($"{nameof(RPC_ShareExploration)}: Received map data from {sender}");
            if (Settings.OthersRevealMap.Value)
            {
                var explored   = z.GetArray();
                var m_explored = Minimap.instance.GetPrivateField <bool[]>("m_explored");
                var bits       = MapCompression.Decompress(explored);

                if (bits.Length != m_explored.Length)
                {
                    Plugin.logger.LogError("mismatched lengths");
                    return;
                }

                var changed = false;
                for (int i = 0; i < bits.Length && i < Minimap.instance.m_textureSize * Minimap.instance.m_textureSize; i++)
                {
                    if (bits[i] && !m_explored[i])
                    {
                        Minimap_Patch.Explore(Minimap.instance, i % Minimap.instance.m_textureSize, i / Minimap.instance.m_textureSize);
                        changed = true;
                    }
                }
                if (changed)
                {
                    Minimap.instance.GetPrivateField <Texture2D>("m_fogTexture").Apply();
                }
            }
        }
Exemple #4
0
    // Token: 0x06000C09 RID: 3081 RVA: 0x000558D4 File Offset: 0x00053AD4
    public void SaveWorldMetaData()
    {
        ZPackage zpackage = new ZPackage();

        zpackage.Write(global::Version.m_worldVersion);
        zpackage.Write(this.m_name);
        zpackage.Write(this.m_seedName);
        zpackage.Write(this.m_seed);
        zpackage.Write(this.m_uid);
        zpackage.Write(this.m_worldGenVersion);
        Directory.CreateDirectory(this.m_worldSavePath);
        string metaPath = this.GetMetaPath();
        string text     = metaPath + ".new";
        string text2    = metaPath + ".old";

        byte[]       array        = zpackage.GetArray();
        FileStream   fileStream   = File.Create(text);
        BinaryWriter binaryWriter = new BinaryWriter(fileStream);

        binaryWriter.Write(array.Length);
        binaryWriter.Write(array);
        binaryWriter.Flush();
        fileStream.Flush(true);
        fileStream.Close();
        fileStream.Dispose();
        if (File.Exists(metaPath))
        {
            if (File.Exists(text2))
            {
                File.Delete(text2);
            }
            File.Move(metaPath, text2);
        }
        File.Move(text, metaPath);
    }
Exemple #5
0
    // Token: 0x06000B5F RID: 2911 RVA: 0x000520EC File Offset: 0x000502EC
    public void SavePlayerData(Player player)
    {
        ZPackage zpackage = new ZPackage();

        player.Save(zpackage);
        this.m_playerData = zpackage.GetArray();
    }
Exemple #6
0
        public byte[] GetMergedMapData(long profileId, bool bMergePins)
        {
            ZPackage zPackage = new ZPackage();

            zPackage.Write(_mapData.m_mapVersion);
            zPackage.Write(_mapData.m_textureSize);

            for (int i = 0; i < (_mapData.m_textureSize * _mapData.m_textureSize); i++)
            {
                zPackage.Write(_mapData.m_mergedWorld[i]);
            }

            List <Pin> pins = _mapData.GetPins(profileId, bMergePins);

            zPackage.Write(pins.Count);
            foreach (Pin p in pins)
            {
                zPackage.Write(p.Name);
                zPackage.Write(p.Pos);
                zPackage.Write((int)p.Type);
                zPackage.Write(p.IsChecked);
            }
            zPackage.Write(_mapData.m_isReferencePositionPublic);
            return(zPackage.GetArray());
        }
Exemple #7
0
    public void SavePlayerData(Player player)
    {
        ZPackage pkg = new ZPackage();

        player.Save(pkg);
        this.m_playerData = pkg.GetArray();
    }
            private static void Postfix(ZNet __instance)
            {
                var l = BepInEx.Logging.Logger.CreateLogSource("ServerSideMap");

                var    world           = Traverse.Create(typeof(ZNet)).Field("m_world").GetValue() as World;
                var    m_worldSavePath = Traverse.Create(world).Field("m_worldSavePath").GetValue() as String;
                string exploredPath    = m_worldSavePath + "/" + world.m_name + ".mod.serversidemap.explored";

                FileStream fileStream;

                try
                {
                    fileStream = File.OpenRead(exploredPath);
                }
                catch
                {
                    var z = new ZPackage();
                    z.Write((int)3);
                    z.Write(mapSize);
                    for (var i = 0; i < mapSize * mapSize; i++)
                    {
                        z.Write(false);
                    }
                    z.Write(0);
                    mapData = z.GetArray();
                    l.LogInfo("new explore file generated");
                    __instance.Save(true);

                    return;
                }
                BinaryReader reader = new BinaryReader((Stream)fileStream);

                mapData = reader.ReadBytes(int.MaxValue);
                l.LogInfo("loaded from existing explore file");
            }
Exemple #9
0
    // Token: 0x060007B8 RID: 1976 RVA: 0x0003C9F0 File Offset: 0x0003ABF0
    public void SaveAsync(BinaryWriter writer)
    {
        writer.Write(this.m_saveData.m_myid);
        writer.Write(this.m_saveData.m_nextUid);
        ZPackage zpackage = new ZPackage();

        writer.Write(this.m_saveData.m_zdos.Count);
        foreach (ZDO zdo in this.m_saveData.m_zdos)
        {
            writer.Write(zdo.m_uid.userID);
            writer.Write(zdo.m_uid.id);
            zpackage.Clear();
            zdo.Save(zpackage);
            byte[] array = zpackage.GetArray();
            writer.Write(array.Length);
            writer.Write(array);
        }
        writer.Write(this.m_saveData.m_deadZDOs.Count);
        foreach (KeyValuePair <ZDOID, long> keyValuePair in this.m_saveData.m_deadZDOs)
        {
            writer.Write(keyValuePair.Key.userID);
            writer.Write(keyValuePair.Key.id);
            writer.Write(keyValuePair.Value);
        }
        ZLog.Log("Saved " + this.m_saveData.m_zdos.Count + " zdos");
        this.m_saveData = null;
    }
    // Token: 0x0600073B RID: 1851 RVA: 0x0003A618 File Offset: 0x00038818
    private void Ping()
    {
        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Broadcast, 6542);
        ZPackage   zpackage = new ZPackage();

        zpackage.Write('F');
        zpackage.Write('E');
        zpackage.Write('J');
        zpackage.Write('D');
        zpackage.Write(this.m_myPort);
        this.m_socket.SendTo(zpackage.GetArray(), remoteEP);
    }
 /// <summary>
 ///     Write ZPackage to file
 /// </summary>
 /// <param name="package"></param>
 /// <param name="filename"></param>
 public static void WriteToFile(this ZPackage package, string filename)
 {
     using (var fs = File.Create(filename))
     {
         using (var bw = new BinaryWriter(fs))
         {
             var data = package.GetArray();
             bw.Write(data.Length);
             bw.Write(data);
         }
     }
 }
        // Decompress (zip) the data
        public static ZPackage Decompress(ZPackage package)
        {
            byte[]       array        = package.GetArray();
            MemoryStream memoryStream = new MemoryStream();
            int          num          = BitConverter.ToInt32(array, 0);

            memoryStream.Write(array, 4, array.Length - 4);
            byte[] array2 = new byte[num];
            memoryStream.Position = 0L;
            new GZipStream(memoryStream, CompressionMode.Decompress).Read(array2, 0, array2.Length);
            return(new ZPackage(array2));
        }
Exemple #13
0
    // Token: 0x06000E1F RID: 3615 RVA: 0x00064C2C File Offset: 0x00062E2C
    private void SaveHealth()
    {
        ZPackage zpackage = new ZPackage();

        zpackage.Write(this.m_hitAreas.Count);
        foreach (MineRock5.HitArea hitArea in this.m_hitAreas)
        {
            zpackage.Write(hitArea.m_health);
        }
        this.m_nview.GetZDO().Set("health", zpackage.GetArray());
        this.m_lastDataRevision = this.m_nview.GetZDO().m_dataRevision;
    }
Exemple #14
0
                public static void Add(ZPackage package)
                {
                    var filePath = GetCachePath(PackageID(package));

                    if (File.Exists(filePath))
                    {
                        LogError($"{filePath} already exists in cache, this shouldn't happen! Deleting the file...");
                        File.Delete(filePath);
                    }
                    Log($"Adding cache entry {filePath}");
                    Directory.CreateDirectory(Path.GetDirectoryName(filePath));
                    File.WriteAllBytes(filePath + ".tmp", package.GetArray());
                    File.Move(filePath + ".tmp", filePath);
                }
 // Token: 0x0600098C RID: 2444 RVA: 0x0004612C File Offset: 0x0004432C
 public void Send(ZPackage pkg)
 {
     if (pkg.Size() == 0)
     {
         return;
     }
     if (!this.IsConnected())
     {
         return;
     }
     byte[] array = pkg.GetArray();
     this.m_sendQueue.Enqueue(array);
     this.SendQueuedPackages();
 }
Exemple #16
0
            public void Save(string path)
            {
                var zpackage = new ZPackage();

                this.Serialize(zpackage);

                byte[] binaryData = zpackage.GetArray();
                Directory.CreateDirectory(Path.GetDirectoryName(path));
                using (BinaryWriter binaryWriter = new BinaryWriter(File.Create(path)))
                {
                    binaryWriter.Write(binaryData.Length);
                    binaryWriter.Write(binaryData);
                }
            }
        // Compress (zip) the data
        public static ZPackage Compress(ZPackage package)
        {
            byte[]       array        = package.GetArray();
            MemoryStream memoryStream = new MemoryStream();
            GZipStream   gzipStream   = new GZipStream(memoryStream, CompressionMode.Compress, true);

            gzipStream.Write(array, 0, array.Length);
            gzipStream.Close();
            memoryStream.Position = 0L;
            byte[] array2 = new byte[memoryStream.Length];
            memoryStream.Read(array2, 0, array2.Length);
            byte[] array3 = new byte[array2.Length + 4];
            Buffer.BlockCopy(array2, 0, array3, 4, array2.Length);
            Buffer.BlockCopy(BitConverter.GetBytes(array.Length), 0, array3, 0, 4);
            return(new ZPackage(array3));
        }
Exemple #18
0
        private IEnumerator NonblockingRPC_OnServerReceive(long sender, ZPackage package)
        {
            Jotunn.Logger.LogMessage($"Received blob, processing");

            string dot = string.Empty;

            for (int i = 0; i < 5; ++i)
            {
                dot += ".";
                Jotunn.Logger.LogMessage(dot);
                yield return(new WaitForSeconds(1f));
            }

            Jotunn.Logger.LogMessage($"Broadcasting to all clients");
            NonblockingRPC.SendPackage(ZNet.instance.m_peers, new ZPackage(package.GetArray()));
        }
        /// <summary>
        ///     Write ZPackage to file
        /// </summary>
        /// <param name="package"></param>
        /// <param name="filename"></param>
        public static void WriteToFile(this ZPackage package, string filename)
        {
            if (!Directory.Exists(Path.GetDirectoryName(filename)))
            {
                Jotunn.Logger.LogInfo($"Creating path {Path.GetDirectoryName(filename)}");
                Directory.CreateDirectory(Path.GetDirectoryName(filename));
            }

            using (var fs = File.Create(filename))
            {
                using (var bw = new BinaryWriter(fs))
                {
                    var data = package.GetArray();
                    bw.Write(data.Length);
                    bw.Write(data);
                }
            }
        }
Exemple #20
0
        // Transmit position, rotation, and velocity information to server
        private void ownerSync()
        {
            if (!VHVRConfig.UseVrControls())
            {
                return;
            }

            ZPackage pkg = new ZPackage();

            writeData(pkg, camera, ownerVelocityCamera);
            writeData(pkg, leftHand, ownerVelocityLeft);
            writeData(pkg, rightHand, ownerVelocityRight);
            writeFingers(pkg, GetComponent <VRIK>().references.leftHand);
            writeFingers(pkg, GetComponent <VRIK>().references.rightHand);
            pkg.Write(BowLocalManager.instance != null && BowLocalManager.instance.pulling);

            GetComponent <ZNetView>().GetZDO().Set("vr_data", pkg.GetArray());
        }
 // Token: 0x060009AB RID: 2475 RVA: 0x0004694C File Offset: 0x00044B4C
 public void Send(ZPackage pkg)
 {
     if (pkg.Size() == 0)
     {
         return;
     }
     if (!this.IsConnected())
     {
         return;
     }
     byte[] array  = pkg.GetArray();
     byte[] bytes  = BitConverter.GetBytes(array.Length);
     byte[] array2 = new byte[array.Length + bytes.Length];
     bytes.CopyTo(array2, 0);
     array.CopyTo(array2, 4);
     this.m_sendQueue.Enqueue(array);
     this.SendQueuedPackages();
 }
Exemple #22
0
    // Token: 0x06000944 RID: 2372 RVA: 0x00044954 File Offset: 0x00042B54
    public void Send(ZPackage pkg)
    {
        if (pkg.Size() == 0)
        {
            return;
        }
        if (this.m_socket == null || !this.m_socket.Connected)
        {
            return;
        }
        byte[] array  = pkg.GetArray();
        byte[] bytes  = BitConverter.GetBytes(array.Length);
        byte[] array2 = new byte[array.Length + bytes.Length];
        bytes.CopyTo(array2, 0);
        array.CopyTo(array2, 4);
        this.m_sendMutex.WaitOne();
        if (!this.m_isSending)
        {
            if (array2.Length > 10485760)
            {
                ZLog.LogError("Too big data package: " + array2.Length);
            }
            try
            {
                this.m_totalSent += array2.Length;
                this.m_socket.GetStream().BeginWrite(array2, 0, array2.Length, new AsyncCallback(this.PkgSent), this.m_socket);
                this.m_isSending = true;
                goto IL_E6;
            }
            catch (Exception arg)
            {
                ZLog.Log("Handled exception in ZSocket:Send:" + arg);
                this.Close();
                goto IL_E6;
            }
        }
        this.m_sendQueue.Enqueue(array2);
IL_E6:
        this.m_sendMutex.ReleaseMutex();
    }
Exemple #23
0
        private IEnumerator BlockingRPC_OnServerReceive(long sender, ZPackage package)
        {
            Jotunn.Logger.LogMessage($"Received blob");

            if (BlockingRPC.IsSending)
            {
                Jotunn.Logger.LogMessage($"RPC is currently broadcasting packages, discarding");
                yield break;
            }

            string dot = string.Empty;

            for (int i = 0; i < 5; ++i)
            {
                dot += ".";
                Jotunn.Logger.LogMessage(dot);
                yield return(new WaitForSeconds(1f));
            }

            Jotunn.Logger.LogMessage($"Broadcasting to all clients");
            BlockingRPC.SendPackage(ZNet.instance.m_peers, new ZPackage(package.GetArray()));
        }
Exemple #24
0
    // Token: 0x0600092A RID: 2346 RVA: 0x000440C8 File Offset: 0x000422C8
    public void Send(ZPackage pkg)
    {
        if (pkg.Size() == 0)
        {
            return;
        }
        if (this.m_socket == null || !this.m_socket.Connected)
        {
            return;
        }
        byte[] array = pkg.GetArray();
        byte[] bytes = BitConverter.GetBytes(array.Length);
        this.m_sendMutex.WaitOne();
        if (!this.m_isSending)
        {
            if (array.Length > 10485760)
            {
                ZLog.LogError("Too big data package: " + array.Length);
            }
            try
            {
                this.m_totalSent += bytes.Length;
                this.m_socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(this.PkgSent), null);
                this.m_isSending = true;
                this.m_sendQueue.Enqueue(array);
                goto IL_DA;
            }
            catch (Exception arg)
            {
                ZLog.Log("Handled exception in ZSocket:Send:" + arg);
                this.Disconnect();
                goto IL_DA;
            }
        }
        this.m_sendQueue.Enqueue(bytes);
        this.m_sendQueue.Enqueue(array);
IL_DA:
        this.m_sendMutex.ReleaseMutex();
    }
Exemple #25
0
        public static void Postfix(ref World __instance, string name)
        {
            if (name == "menu")
            {
                return;
            }
            ZPackage biomePackage = new ZPackage();

            WorldGenOptions.GenOptions.savedData.WriteBiomeData(ref biomePackage);

            string biomePath = SavingData.GetBiomeSavePath(__instance);

            byte[]       biomeArray        = biomePackage.GetArray();
            FileStream   biomeStream       = File.Create(biomePath);
            BinaryWriter biomeBinaryWriter = new BinaryWriter(biomeStream);

            biomeBinaryWriter.Write(biomeArray.Length);
            biomeBinaryWriter.Write(biomeArray);
            biomeBinaryWriter.Flush();
            biomeStream.Flush(true);
            biomeStream.Close();
            biomeStream.Dispose();
        }
        public static void Postfix()
        {
            try {
                // proof of concept persistence, don't want to include or test it now
                return;

                //TODO: Only do this if we're the server.
                Plugin.Logger.LogInfo("Persisting armorstand db");

                var armorStandsZDOs = new List <ZDO>();
                ZDOMan.instance.GetAllZDOsWithPrefab("FullArmorStand", armorStandsZDOs);

                var zpkg     = new ZPackage();
                var fileName = ZNet.m_world.m_name + ".armorstands.db"; //make a variable

                using (BinaryWriter writer = new BinaryWriter(File.Open(World.GetWorldSavePath() + "/" + fileName, FileMode.OpenOrCreate))) {
                    writer.Write(Version.m_worldVersion); //int32
                    writer.Write(armorStandsZDOs.Count);  //int32

                    foreach (var zdo in armorStandsZDOs)
                    {
                        writer.Write(zdo.m_uid.userID); //long
                        writer.Write(zdo.m_uid.id);     //uint32

                        zpkg.Clear();
                        zdo.Save(zpkg);

                        byte[] array = zpkg.GetArray();
                        writer.Write(array.Length);//int32
                        writer.Write(array);
                        Plugin.Logger.LogInfo("Persisting armor stand with id " + zdo.m_uid);
                    }
                }
            }catch (Exception exc) {
                Plugin.Logger.LogError("Error saving backup data: " + exc);
            }
        }
Exemple #27
0
    private bool SavePlayerToDisk()
    {
        Directory.CreateDirectory(Utils.GetSaveDataPath() + "/characters");
        string   str1     = Utils.GetSaveDataPath() + "/characters/" + this.m_filename + ".fch";
        string   str2     = Utils.GetSaveDataPath() + "/characters/" + this.m_filename + ".fch.old";
        string   str3     = Utils.GetSaveDataPath() + "/characters/" + this.m_filename + ".fch.new";
        ZPackage zpackage = new ZPackage();

        zpackage.Write(Version.m_playerVersion);
        zpackage.Write(this.m_playerStats.m_kills);
        zpackage.Write(this.m_playerStats.m_deaths);
        zpackage.Write(this.m_playerStats.m_crafts);
        zpackage.Write(this.m_playerStats.m_builds);
        zpackage.Write(this.m_worldData.Count);
        foreach (KeyValuePair <long, PlayerProfile.WorldPlayerData> keyValuePair in this.m_worldData)
        {
            zpackage.Write(keyValuePair.Key);
            zpackage.Write(keyValuePair.Value.m_haveCustomSpawnPoint);
            zpackage.Write(keyValuePair.Value.m_spawnPoint);
            zpackage.Write(keyValuePair.Value.m_haveLogoutPoint);
            zpackage.Write(keyValuePair.Value.m_logoutPoint);
            zpackage.Write(keyValuePair.Value.m_haveDeathPoint);
            zpackage.Write(keyValuePair.Value.m_deathPoint);
            zpackage.Write(keyValuePair.Value.m_homePoint);
            zpackage.Write(keyValuePair.Value.m_mapData != null);
            if (keyValuePair.Value.m_mapData != null)
            {
                zpackage.Write(keyValuePair.Value.m_mapData);
            }
        }
        zpackage.Write(this.m_playerName);
        zpackage.Write(this.m_playerID);
        zpackage.Write(this.m_startSeed);
        if (this.m_playerData != null)
        {
            zpackage.Write(true);
            zpackage.Write(this.m_playerData);
        }
        else
        {
            zpackage.Write(false);
        }
        byte[]       hash         = zpackage.GenerateHash();
        byte[]       array        = zpackage.GetArray();
        FileStream   fileStream   = File.Create(str3);
        BinaryWriter binaryWriter = new BinaryWriter((Stream)fileStream);

        binaryWriter.Write(array.Length);
        binaryWriter.Write(array);
        binaryWriter.Write(hash.Length);
        binaryWriter.Write(hash);
        binaryWriter.Flush();
        fileStream.Flush(true);
        fileStream.Close();
        fileStream.Dispose();
        if (File.Exists(str1))
        {
            if (File.Exists(str2))
            {
                File.Delete(str2);
            }
            File.Move(str1, str2);
        }
        File.Move(str3, str1);
        return(true);
    }
Exemple #28
0
            private static IEnumerator SendSettings(ZNet instance, ZRpc rpc, ZPackage pkg)
            {
                byte[] ArraySlice(byte[] source, int offset, int length)
                {
                    var target = new byte[length];

                    Buffer.BlockCopy(source, offset, target, 0, length);
                    return(target);
                }

                var peer = instance.GetPeers().First(p => p.m_rpc == rpc);

                if (!Settings.EnabledForThisWorld)
                {
                    Log($"Skipping sending settings to {PeerName(peer)}, as Better Continents is not enabled in this world");
                }
                else
                {
                    Log($"World is using Better Continents, so client version must match server version {ModInfo.Name}");

                    if (!ClientInfo.TryGetValue(peer.m_uid, out var bcClientInfo))
                    {
                        Log($"Client info for {PeerName(peer)} not found, client has an old version of Better Continents, or none!");
                        rpc.Invoke("Error", ZNet.ConnectionStatus.ErrorConnectFailed);
                        ZNet.instance.Disconnect(peer);
                        yield break;
                    }
                    else if (bcClientInfo.version != ModInfo.Version)
                    {
                        Log($"Client {PeerName(peer)} version {bcClientInfo.version} doesn't match server version {ModInfo.Version}");
                        peer.m_rpc.Invoke("Error", 69);
                        ZNet.instance.Disconnect(peer);
                        yield break;
                    }
                    else
                    {
                        Log($"Client {PeerName(peer)} version {bcClientInfo.version} matches server version {ModInfo.Version}");
                    }

                    // This was the initial way that versioning was implemented, before the client->server way, so may
                    // as well leave it in
                    Log($"Sending server version {ModInfo.Version} to client for bi-lateral version agreement");
                    rpc.Invoke("BetterContinentsVersion", ModInfo.Version);

                    var settingsPackage = new ZPackage();
                    var cleanSettings   = Settings.Clean();
                    cleanSettings.Serialize(settingsPackage);

                    if (WorldCache.CacheItemExists(settingsPackage, bcClientInfo.worldCache))
                    {
                        // We send hash and id
                        string cacheId = WorldCache.PackageID(settingsPackage);
                        Log($"Client {PeerName(peer)} already has cached settings for world, instructing it to load those (id {cacheId})");
                        rpc.Invoke("BetterContinentsConfigLoadFromCache", cacheId);
                    }
                    else
                    {
                        Log($"Client {PeerName(peer)} doesn't have cached settings, sending them now");
                        cleanSettings.Dump();

                        var settingsData = settingsPackage.GetArray();
                        Log($"Sending settings package header for {settingsData.Length} byte stream");
                        rpc.Invoke("BetterContinentsConfigStart", settingsData.Length, GetHashCode(settingsData));

                        const int SendChunkSize = 256 * 1024;

                        for (int sentBytes = 0; sentBytes < settingsData.Length;)
                        {
                            int packetSize = Mathf.Min(settingsData.Length - sentBytes, SendChunkSize);
                            var packet     = ArraySlice(settingsData, sentBytes, packetSize);
                            rpc.Invoke("BetterContinentsConfigPacket", sentBytes, GetHashCode(packet),
                                       new ZPackage(packet));
                            // Make sure to flush or we will saturate the queue...
                            rpc.GetSocket().Flush();
                            sentBytes += packetSize;
                            Log($"Sent {sentBytes} of {settingsData.Length} bytes");
                            float timeout = Time.time + 30;
                            yield return(new WaitUntil(() => rpc.GetSocket().GetSendQueueSize() < SendChunkSize || Time.time > timeout));

                            if (Time.time > timeout)
                            {
                                Log($"Timed out sending config to client {PeerName(peer)} after 30 seconds, disconnecting them");
                                peer.m_rpc.Invoke("Error", ZNet.ConnectionStatus.ErrorConnectFailed);
                                ZNet.instance.Disconnect(peer);
                                yield break;
                            }
                        }
                    }
                    yield return(new WaitUntil(() => ClientInfo[peer.m_uid].readyForPeerInfo || !peer.m_socket.IsConnected()));
                }

                RPC_PeerInfo(instance, rpc, pkg);
            }
        public bool LoadPlayerFromDisk(out string error)
        {
            error = string.Empty;
            ZPackage zPackage = LoadPlayerDataFromDisk();
            //backup
            DirectoryInfo dir = Directory.CreateDirectory("backup");

            File.WriteAllBytes($"{dir.FullName}/{m_filename}", zPackage.GetArray());

            if (zPackage == null)
            {
                error = "No player data";
                return(false);
            }

            m_version = zPackage.ReadInt();
            if (!VersionInfo.IsPlayerVersionCompatible(m_version))
            {
                error = "Player data is not compatible, ignoring";
                return(false);
            }

            if (m_version >= 28)
            {
                m_playerStats.m_kills  = zPackage.ReadInt();
                m_playerStats.m_deaths = zPackage.ReadInt();
                m_playerStats.m_crafts = zPackage.ReadInt();
                m_playerStats.m_builds = zPackage.ReadInt();
            }

            int num2 = zPackage.ReadInt();

            for (int i = 0; i < num2; i++)
            {
                long            key             = zPackage.ReadLong();
                WorldPlayerData worldPlayerData = new WorldPlayerData();

                worldPlayerData.m_haveCustomSpawnPoint = zPackage.ReadBool();
                worldPlayerData.m_spawnPoint           = zPackage.ReadVector3();
                worldPlayerData.m_haveLogoutPoint      = zPackage.ReadBool();
                worldPlayerData.m_logoutPoint          = zPackage.ReadVector3();
                if (m_version >= 30)
                {
                    worldPlayerData.m_haveDeathPoint = zPackage.ReadBool();
                    worldPlayerData.m_deathPoint     = zPackage.ReadVector3();
                }
                worldPlayerData.m_homePoint = zPackage.ReadVector3();
                if (m_version >= 29 && zPackage.ReadBool())
                {
                    worldPlayerData.m_mapData = zPackage.ReadByteArray();
                }
                m_worldData.Add(key, worldPlayerData);
            }

            m_playerName = zPackage.ReadString();
            m_playerID   = zPackage.ReadLong();
            m_startSeed  = zPackage.ReadString();

            m_playerData = null;
            if (zPackage.ReadBool())
            {
                m_playerData = zPackage.ReadByteArray();
            }

            return(true);
        }
        public bool MergeToDisk(long worldId, List <PlayerProfile> profiles)
        {
            try
            {
                ZPackage zPackage = new ZPackage();
                zPackage.Write(m_version);
                zPackage.Write(m_playerStats.m_kills);
                zPackage.Write(m_playerStats.m_deaths);
                zPackage.Write(m_playerStats.m_crafts);
                zPackage.Write(m_playerStats.m_builds);
                zPackage.Write(m_worldData.Count);
                foreach (KeyValuePair <long, WorldPlayerData> current in m_worldData)
                {
                    zPackage.Write(current.Key);
                    zPackage.Write(current.Value.m_haveCustomSpawnPoint);
                    zPackage.Write(current.Value.m_spawnPoint);
                    zPackage.Write(current.Value.m_haveLogoutPoint);
                    zPackage.Write(current.Value.m_logoutPoint);
                    zPackage.Write(current.Value.m_haveDeathPoint);
                    zPackage.Write(current.Value.m_deathPoint);
                    zPackage.Write(current.Value.m_homePoint);
                    zPackage.Write(current.Value.m_mapData != null);
                    if (current.Value.m_mapData != null)
                    {
                        if (current.Key == worldId)
                        {
                            for (int i = 8; i < (2048 * 2048); i++)
                            {
                                bool bVal = Convert.ToBoolean(current.Value.m_mapData[i]);
                                foreach (var p in profiles)
                                {
                                    if (p == this)
                                    {
                                        continue;
                                    }

                                    bVal = bVal || Convert.ToBoolean(p.m_worldData[current.Key].m_mapData[i]);
                                }
                                current.Value.m_mapData[i] = Convert.ToByte(bVal);
                            }
                        }
                        zPackage.Write(current.Value.m_mapData);
                    }
                }
                zPackage.Write(m_playerName);
                zPackage.Write(m_playerID);
                zPackage.Write(m_startSeed);
                if (m_playerData != null)
                {
                    zPackage.Write(true);
                    zPackage.Write(m_playerData);
                }
                else
                {
                    zPackage.Write(false);
                }
                byte[] array  = zPackage.GenerateHash();
                byte[] array2 = zPackage.GetArray();
                Directory.CreateDirectory("merge");
                FileStream   expr_221 = File.Create($"merge/{m_filename}");
                BinaryWriter expr_227 = new BinaryWriter(expr_221);
                expr_227.Write(array2.Length);
                expr_227.Write(array2);
                expr_227.Write(array.Length);
                expr_227.Write(array);
                expr_227.Flush();
                expr_221.Flush(true);
                expr_221.Close();
                expr_221.Dispose();

                return(true);
            }
            catch (Exception ex)
            {
                return(false);
            }
        }