public void Update(GameTime gameTime) { var any = false; Mesh _mesh; while (IncomingChunks.TryTake(out _mesh)) { any = true; var mesh = _mesh as ChunkMesh; if (ActiveMeshes.Contains(mesh.Chunk.Coordinates)) { int existing = ChunkMeshes.FindIndex(m => m.Chunk.Coordinates == mesh.Chunk.Coordinates); ChunkMeshes[existing] = mesh; } else { ActiveMeshes.Add(mesh.Chunk.Coordinates); ChunkMeshes.Add(mesh); } } if (any) { Game.FlushMainThreadActions(); } WorldLighting.TryLightNext(); }
//reading data chunks public override void Start() { StartTime = DateTime.Now; try { using (var inFileStream = new FileStream(InFileName, FileMode.Open)) { InFileStream = inFileStream; for (ChunkCounter = 0; inFileStream.Length - inFileStream.Position > 0; ChunkCounter++) { if (StopRequested) { return; } //check the percentage of remaining memory to initial while ((float)CompInfo.AvailablePhysicalMemory / InitialFreeRam < 0.1) { //forcing garbage collector cleanup GC.Collect(2, GCCollectionMode.Forced); Thread.Sleep(1000); } //optimal data read chunk size based on ram and cpu cores var dataChunkSize = (long)CompInfo.AvailablePhysicalMemory / CoreCount / 1; //size of chunk for the last chunck if (inFileStream.Length - inFileStream.Position <= dataChunkSize) { dataChunkSize = inFileStream.Length - inFileStream.Position; } //size of chunk for small files if (inFileStream.Length < dataChunkSize) { dataChunkSize = inFileStream.Length / CoreCount + 1; } //constant size of chunk for huge files if (dataChunkSize > 256 * 1024 * 1024) { dataChunkSize = 256 * 1024 * 1024; } var dataChunk = new byte[dataChunkSize]; //read file inFileStream.Read(dataChunk, 0, (int)dataChunkSize); lock (Locker) IncomingChunks.Add(ChunkCounter, dataChunk); //starting new thread with chunk number as an argument var chunkNumber = ChunkCounter; var compressThread = new Thread(() => ProcessChunk(chunkNumber)); compressThread.Start(); } IncomingFinished = true; } } catch (Exception ex) { StopRequested = true; Console.Write("There is the problem at the compression process:{0}", ex.Message); } }
protected override void Update(GameTime gameTime) { GameTime = gameTime; foreach (var i in Interfaces) { i.Update(gameTime); } Mesh mesh; while (IncomingChunks.TryTake(out mesh)) { ChunkMeshes.Add(mesh); } Action action; if (PendingMainThreadActions.TryTake(out action)) { action(); } if (NextPhysicsUpdate < DateTime.UtcNow && Client.LoggedIn) { IChunk chunk; var adjusted = Client.World.World.FindBlockPosition(new Coordinates3D((int)Client.Position.X, 0, (int)Client.Position.Z), out chunk); if (chunk != null) { if (chunk.GetHeight((byte)adjusted.X, (byte)adjusted.Z) != 0) { Client.Physics.Update(); } } // NOTE: This is to make the vanilla server send us chunk packets // We should eventually make some means of detecing that we're on a vanilla server to enable this // It's a waste of bandwidth to do it on a TrueCraft server Client.QueuePacket(new PlayerGroundedPacket { OnGround = true }); Client.QueuePacket(new PlayerPositionAndLookPacket(Client.Position.X, Client.Position.Y, Client.Position.Y + MultiplayerClient.Height, Client.Position.Z, Client.Yaw, Client.Pitch, false)); NextPhysicsUpdate = DateTime.UtcNow.AddMilliseconds(1000 / 20); } if (Delta != Microsoft.Xna.Framework.Vector3.Zero) { var lookAt = Microsoft.Xna.Framework.Vector3.Transform( Delta, Matrix.CreateRotationY(Microsoft.Xna.Framework.MathHelper.ToRadians(Client.Yaw))); Client.Position += new TrueCraft.API.Vector3(lookAt.X, lookAt.Y, lookAt.Z) * (gameTime.ElapsedGameTime.TotalSeconds * 4.3717); } base.Update(gameTime); }
//compress data chunk protected override void ProcessChunk(int chunkNumber) { if (StopRequested) { return; } ProcessSemaphore.WaitOne(); try { KeyValuePair <int, byte[]> chunk; lock (Locker) chunk = IncomingChunks.FirstOrDefault(b => b.Key == chunkNumber); //stream for processed data using (var outMemStream = new MemoryStream()) { using (var zipStream = new GZipStream(outMemStream, CompressionMode.Compress)) { using (var inMemStream = new MemoryStream(chunk.Value, 0, chunk.Value.Length)) { inMemStream.CopyTo(zipStream); } } //compressed bytes var bytes = outMemStream.ToArray(); lock (Locker) { //add new data chunk to collection of compressed data OutgoingChunks.Add(chunkNumber, bytes); //remove chunk from collection of uncompressed data IncomingChunks.Remove(chunkNumber); } } } catch (Exception ex) { StopRequested = true; Console.Write("There is an exception at the compressing process: {0}", ex.Message); } ProcessSemaphore.Release(); //if this is the first chunk - start writing to disk in a separate thread if (chunkNumber == 0 && WritingThread.ThreadState != ThreadState.Running && !StopRequested) { WritingThread.Start(); } }
//read compressed data chunks from disk public override void Start() { StartTime = DateTime.Now; try { using (var inFileStream = new FileStream(InFileName, FileMode.Open)) { InFileStream = inFileStream; var header = new byte[8]; for (ChunkCounter = 0; inFileStream.Length - inFileStream.Position > 0; ChunkCounter++) { if (StopRequested) { return; } //ram overload - wait while ((float)CompInfo.AvailablePhysicalMemory / InitialFreeRam < 0.1) { //force gc cleanup GC.Collect(2, GCCollectionMode.Forced); Thread.Sleep(1000); } //extract compressed data chunk size from gzip header inFileStream.Read(header, 0, 8); var dataChunkSize = BitConverter.ToInt32(header, 4); var compressedChunk = new byte[dataChunkSize]; header.CopyTo(compressedChunk, 0); //get the rest bytes of data block inFileStream.Read(compressedChunk, 8, dataChunkSize - 9); lock (Locker) IncomingChunks.Add(ChunkCounter, compressedChunk); var chunkNumber = ChunkCounter; var decompressThread = new Thread(() => ProcessChunk(chunkNumber)); decompressThread.Start(); } IncomingFinished = true; } } catch (Exception ex) { StopRequested = true; Console.Write("There is tecompression process:{0}", ex.Message); } }
void MeshCompleted(object sender, RendererEventArgs <ReadOnlyChunk> e) { IncomingChunks.Add(e.Result); }
void ChunkConverter_MeshGenerated(object sender, RendererEventArgs <ReadOnlyChunk> e) { IncomingChunks.Add(e.Result); }