private void ProcessRequest(ref CubeRequest processingRequest)
        {
            _landscapeGetCmd.Parameters[0].Value = processingRequest.ChunkId.X;
            _landscapeGetCmd.Parameters[1].Value = processingRequest.ChunkId.Y;
            _landscapeGetCmd.Parameters[2].Value = processingRequest.ChunkId.Z;

            ChunkDataStorage cubeDataStorage = null;

            using (var dataReader = _landscapeGetCmd.ExecuteReader())
            {
                if (dataReader.Read())
                {
                    cubeDataStorage = new ChunkDataStorage
                    {
                        ChunkPos = new Vector3I(dataReader.GetInt32(0), dataReader.GetInt32(1), dataReader.GetInt32(2)),
                        Md5Hash  = !dataReader.IsDBNull(3) ? new Md5Hash((byte[])dataReader.GetValue(3)) : null,
                        CubeData = (byte[])dataReader.GetValue(4)
                    };
                }
            }

            Data[processingRequest.Ticket] = cubeDataStorage;
        }
        //GET + REQUEST Chunk DATA ======================================================================
        private void ChunkStorageManagerInit()
        {
            Data              = new ChunkDataStorage[_nbrTicket + 1];
            _requestTickets   = new BlockingCollection <int>(_nbrTicket);
            _dataRequestQueue = new ConcurrentQueue <CubeRequest>();
            _dataStoreQueue   = new ConcurrentQueue <ChunkDataStorage>();

            //Create the tickets and the Data Holder From 1 To _nbrTicket.
            for (int i = 1; i <= _nbrTicket; i++)
            {
                _requestTickets.Add(i);
                Data[i] = null;
            }

            //Get a specific chunk
            var commandText = "SELECT [X], [Y], [Z], [md5hash], [data] FROM CHUNKS WHERE (X = @X AND Y = @Y AND Z = @Z)";

            _landscapeGetCmd = new SQLiteCommand(commandText, Connection);
            _landscapeGetCmd.Parameters.Add("@X", System.Data.DbType.Int32);
            _landscapeGetCmd.Parameters.Add("@Y", System.Data.DbType.Int32);
            _landscapeGetCmd.Parameters.Add("@Z", System.Data.DbType.Int32);

            //Get All modified chunks Hashs
            commandText       = "SELECT [X], [Y], [Z], [md5hash] FROM CHUNKS";
            _landscapeGetHash = new SQLiteCommand(commandText, Connection);

            //Upsert a specific chunk
            commandText         = "INSERT OR REPLACE INTO CHUNKS ([X], [Y], [Z], [md5hash], [data]) VALUES (@X, @Y, @Z, @MD5, @DATA)";
            _landscapeInsertCmd = new SQLiteCommand(commandText, Connection);
            _landscapeInsertCmd.Parameters.Add("@X", System.Data.DbType.Int32);
            _landscapeInsertCmd.Parameters.Add("@Y", System.Data.DbType.Int32);
            _landscapeInsertCmd.Parameters.Add("@Z", System.Data.DbType.Int32);
            _landscapeInsertCmd.Parameters.Add("@MD5", System.Data.DbType.Binary);
            _landscapeInsertCmd.Parameters.Add("@DATA", System.Data.DbType.Binary);

            _threadSync = new ManualResetEvent(false);
        }
        private void SaveObject(ref ChunkDataStorage data)
        {
            _landscapeInsertCmd.Parameters[0].Value = data.ChunkPos.X;
            _landscapeInsertCmd.Parameters[1].Value = data.ChunkPos.Y;
            _landscapeInsertCmd.Parameters[2].Value = data.ChunkPos.Z;
            if (data.Md5Hash != null)
            {
                _landscapeInsertCmd.Parameters[3].Value = data.Md5Hash.Bytes;
            }
            else
            {
                _landscapeInsertCmd.Parameters[3].Value = null;
            }
            _landscapeInsertCmd.Parameters[4].Value = data.CubeData; //Chunk + Entities Data under compressed form stored

            _landscapeInsertCmd.ExecuteNonQuery();

            //Add or update the Dictionnary
            //The dictionnary reflect the Chunks saved on SQLite database.
            //For a specified ChunkID it give the MD5Hash.
            var chunkHash = data.Md5Hash;

            ChunkHashes.AddOrUpdate(data.ChunkPos, chunkHash, (id, hash) => chunkHash);
        }
        //===============================================================================================

        //Set Chunk Data ================================================================================
        public void StoreData_async(ChunkDataStorage data)
        {
            _dataStoreQueue.Enqueue(data);

            _threadSync.Set();
        }
Beispiel #5
0
        private void CheckServerReceivedData(VisualChunk chunk)
        {
            //Is this chunk server requested ==> Then check if the result is buffered
            if (chunk.IsServerRequested)
            {
                ChunkDataMessage message;
                //Have we receive the Server data
                if (_receivedServerChunks.TryGetValue(chunk.Position, out message))
                {
                    if (chunk.IsServerResyncMode)
                    {
                        if (message.Flag != ChunkDataMessageFlag.ChunkWasModified)
                        {
                            //Do nothing we are still in sync !
                            chunk.IsServerRequested  = false;
                            chunk.IsServerResyncMode = false;
                            lock (_syncRoot) _receivedServerChunks.Remove(chunk.Position); //Remove the sync from the recieved queue
                            //logger.Debug("Chunk Processed {0} - Resync Mode  !", chunk.Position);
                            return;
                        }
                        else
                        {
                            chunk.State = ChunkState.MeshesChanged;
                            var chunkHash = chunk.GetMd5Hash();
                            logger.Debug("[Chunk Resync] {0} - was DESYNC with server [{1}] !", chunk.Position, message.Flag.ToString());
                        }
                    }

                    switch (message.Flag)
                    {
                    //In this case the message contains the data from the landscape !
                    case ChunkDataMessageFlag.ChunkWasModified:

                        var networkChunk = new CompressibleChunk(new InsideDataProvider());
                        networkChunk.Decompress(message.Data);

                        chunk.Consume(networkChunk);     //Set the data into the "Big Array"
                        EntityFactory.PrepareEntities(chunk.Entities);

                        lock (_syncRoot)
                        {
                            _receivedServerChunks.Remove(chunk.Position);     //Remove the chunk from the recieved queue
                            //logger.Debug("Chunk Processed {0} - ChunkWasModified  !", chunk.Position);
                        }

                        //Save the modified chunk landscape data locally only if the local one is different from the server one
                        Md5Hash hash;
                        bool    saveChunk = true;
                        if (_chunkStorageManager.ChunkHashes.TryGetValue(chunk.Position, out hash))
                        {
                            if (hash == message.ChunkHash)
                            {
                                saveChunk = false;
                            }
                        }

                        if (saveChunk)
                        {
                            _chunkStorageManager.StoreData_async(new ChunkDataStorage
                            {
                                ChunkPos = chunk.Position,
                                Md5Hash  = message.ChunkHash,
                                CubeData = chunk.Compress()
                            }
                                                                 );
                        }

                        if (chunk.StorageRequestTicket != 0)
                        {
                            _chunkStorageManager.FreeTicket(chunk.StorageRequestTicket);
                            chunk.StorageRequestTicket = 0;
                        }

                        break;

                    case ChunkDataMessageFlag.ChunkCanBeGenerated:

                        CreateLandscapeFromGenerator(chunk);
                        lock (_syncRoot)
                        {
                            _receivedServerChunks.Remove(chunk.Position);
                            //logger.Debug("Chunk Processed {0} - ChunkCanBeGenerated  !", chunk.Position);
                        }
                        if (chunk.StorageRequestTicket != 0)
                        {
                            _chunkStorageManager.FreeTicket(chunk.StorageRequestTicket);
                            chunk.StorageRequestTicket = 0;
                        }
                        break;

                    case ChunkDataMessageFlag.ChunkMd5Equal:
                        //Do we still have to wait for the chunk from the local storage ??
                        ChunkDataStorage data = _chunkStorageManager.Data[chunk.StorageRequestTicket];
                        if (data != null)
                        {
                            //Data are present !
                            chunk.Decompress(data.CubeData);     //Set the data into the "Big Array"
                            lock (_syncRoot)
                            {
                                _receivedServerChunks.Remove(chunk.Position);     //Remove the chunk from the recieved queue
                                //logger.Debug("Chunk Processed {0} - ChunkMd5Equal  !", chunk.Position);
                            }
                            EntityFactory.PrepareEntities(chunk.Entities);

                            if (chunk.StorageRequestTicket != 0)
                            {
                                _chunkStorageManager.FreeTicket(chunk.StorageRequestTicket);
                                chunk.StorageRequestTicket = 0;
                            }
                        }
                        break;

                    default:
                        break;
                    }

                    chunk.RefreshBorderChunk();
                    chunk.IsServerRequested  = false;
                    chunk.IsServerResyncMode = false;
                    chunk.State = ChunkState.LandscapeCreated;
                }
            }
            else
            {
#if DEBUG
                logger.Trace("Chunk request to server : " + chunk.Position);
#endif
                //Request Chunk to the server, to see its server State (Was it modified by someone Else ???)

                chunk.IsServerRequested = true;
                Md5Hash hash;
                if (_chunkStorageManager.ChunkHashes.TryGetValue(chunk.Position, out hash))
                {
                    //Ask the chunk Data to the DB, in case my local MD5 is equal to the server one. This way the server won't have to send back the chunk data
                    chunk.StorageRequestTicket = _chunkStorageManager.RequestDataTicket_async(chunk.Position);

                    //We have already in the store manager a modified version of the chunk, do the server request with these information
                    _server.ServerConnection.Send(new GetChunksMessage
                    {
                        HashesCount = 1,
                        Md5Hashes   = new[] { hash },
                        Positions   = new[] { chunk.Position },
                        Range       = new Range3I(chunk.Position, Vector3I.One),
                        Flag        = GetChunksMessageFlag.DontSendChunkDataIfNotModified
                    });
                }
                else
                {
                    //Chunk has never been modified. Request it by the chunkposition to the server
                    _server.ServerConnection.Send(new GetChunksMessage
                    {
                        Range = new Range3I(chunk.Position, Vector3I.One),
                        Flag  = GetChunksMessageFlag.DontSendChunkDataIfNotModified
                    });
                }
            }
        }