mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-24 05:03:34 -04:00
Optimise level sending - instead of compressing to temp memorystream, compress directly to network.
This commit is contained in:
parent
16a1b372e4
commit
eed355e7af
@ -513,6 +513,7 @@
|
|||||||
<Compile Include="Levels\Physics\TntPhysics.cs" />
|
<Compile Include="Levels\Physics\TntPhysics.cs" />
|
||||||
<Compile Include="Levels\Physics\ZombiePhysics.cs" />
|
<Compile Include="Levels\Physics\ZombiePhysics.cs" />
|
||||||
<Compile Include="Levels\Zones.cs" />
|
<Compile Include="Levels\Zones.cs" />
|
||||||
|
<Compile Include="Network\LevelChunkStream.cs" />
|
||||||
<Compile Include="Player\Chat.cs" />
|
<Compile Include="Player\Chat.cs" />
|
||||||
<Compile Include="Player\Entities.cs" />
|
<Compile Include="Player\Entities.cs" />
|
||||||
<Compile Include="Player\Group\Group.cs" />
|
<Compile Include="Player\Group\Group.cs" />
|
||||||
|
85
Network/LevelChunkStream.cs
Normal file
85
Network/LevelChunkStream.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 MCGalaxy
|
||||||
|
|
||||||
|
Dual-licensed under the Educational Community License, Version 2.0 and
|
||||||
|
the GNU General Public License, Version 3 (the "Licenses"); you may
|
||||||
|
not use this file except in compliance with the Licenses. You may
|
||||||
|
obtain a copy of the Licenses at
|
||||||
|
|
||||||
|
http://www.opensource.org/licenses/ecl2.php
|
||||||
|
http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the Licenses are distributed on an "AS IS"
|
||||||
|
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||||
|
or implied. See the Licenses for the specific language governing
|
||||||
|
permissions and limitations under the Licenses.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace MCGalaxy {
|
||||||
|
public sealed class LevelChunkStream : Stream {
|
||||||
|
public override bool CanRead { get { return false; } }
|
||||||
|
public override bool CanSeek { get { return false; } }
|
||||||
|
public override bool CanWrite { get { return true; } }
|
||||||
|
|
||||||
|
static Exception ex = new NotSupportedException("Stream does not support length/seeking.");
|
||||||
|
public override void Flush() { }
|
||||||
|
public override long Length { get { throw ex; } }
|
||||||
|
public override long Position { get { throw ex; } set { throw ex; } }
|
||||||
|
public override int Read(byte[] buffer, int offset, int count) { throw ex; }
|
||||||
|
public override long Seek(long offset, SeekOrigin origin) { throw ex; }
|
||||||
|
public override void SetLength(long length) { throw ex; }
|
||||||
|
|
||||||
|
internal int index, position, length;
|
||||||
|
Player p;
|
||||||
|
byte[] data = new byte[chunkSize + 4];
|
||||||
|
const int chunkSize = 1024;
|
||||||
|
|
||||||
|
public LevelChunkStream(Player p) {
|
||||||
|
this.p = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close() {
|
||||||
|
if (index > 0) WritePacket();
|
||||||
|
p = null;
|
||||||
|
base.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count) {
|
||||||
|
while (count > 0) {
|
||||||
|
int copy = Math.Min(chunkSize - index, count);
|
||||||
|
if (copy <= 8) {
|
||||||
|
for (int i = 0; i < copy; i++)
|
||||||
|
data[index + i + 3] = buffer[offset + i];
|
||||||
|
} else {
|
||||||
|
Buffer.BlockCopy(buffer, offset, data, index + 3, copy);
|
||||||
|
}
|
||||||
|
offset += copy; index += copy; count -= copy;
|
||||||
|
|
||||||
|
if (index != chunkSize) continue;
|
||||||
|
WritePacket();
|
||||||
|
data = new byte[chunkSize + 4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteByte(byte value) {
|
||||||
|
data[index + 3] = value;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (index != chunkSize) return;
|
||||||
|
WritePacket();
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WritePacket() {
|
||||||
|
data[0] = Opcode.LevelDataChunk;
|
||||||
|
NetUtils.WriteU16((ushort)index, data, 1);
|
||||||
|
data[1027] = (byte)(100 * (float)position / length);
|
||||||
|
p.SendRaw(data);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -343,9 +343,6 @@ namespace MCGalaxy {
|
|||||||
lastCheckpointIndex = -1;
|
lastCheckpointIndex = -1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int usedLength = 0;
|
|
||||||
byte[] buffer = CompressRawMap(out usedLength);
|
|
||||||
|
|
||||||
if (hasBlockDefs) {
|
if (hasBlockDefs) {
|
||||||
if (oldLevel != null && oldLevel != level)
|
if (oldLevel != null && oldLevel != level)
|
||||||
RemoveOldLevelCustomBlocks(oldLevel);
|
RemoveOldLevelCustomBlocks(oldLevel);
|
||||||
@ -353,22 +350,10 @@ namespace MCGalaxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SendRaw(Opcode.LevelInitialise);
|
SendRaw(Opcode.LevelInitialise);
|
||||||
int totalRead = 0;
|
using (LevelChunkStream s = new LevelChunkStream(this))
|
||||||
while (totalRead < usedLength) {
|
CompressRawMap(s);
|
||||||
byte[] packet = new byte[1028]; // need each packet separate for Mono
|
|
||||||
packet[0] = Opcode.LevelDataChunk;
|
|
||||||
short length = (short)Math.Min(buffer.Length - totalRead, 1024);
|
|
||||||
NetUtils.WriteI16(length, packet, 1);
|
|
||||||
Buffer.BlockCopy(buffer, totalRead, packet, 3, length);
|
|
||||||
packet[1027] = (byte)(100 * (float)totalRead / buffer.Length);
|
|
||||||
|
|
||||||
SendRaw(packet);
|
byte[] buffer = new byte[7];
|
||||||
if (ip != "127.0.0.1")
|
|
||||||
Thread.Sleep(Server.updateTimer.Interval > 1000 ? 100 : 10);
|
|
||||||
totalRead += length;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = new byte[7];
|
|
||||||
buffer[0] = Opcode.LevelFinalise;
|
buffer[0] = Opcode.LevelFinalise;
|
||||||
NetUtils.WriteI16((short)level.Width, buffer, 1);
|
NetUtils.WriteI16((short)level.Width, buffer, 1);
|
||||||
NetUtils.WriteI16((short)level.Height, buffer, 3);
|
NetUtils.WriteI16((short)level.Height, buffer, 3);
|
||||||
@ -403,10 +388,9 @@ namespace MCGalaxy {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe byte[] CompressRawMap(out int usedLength) {
|
unsafe void CompressRawMap(LevelChunkStream dst) {
|
||||||
const int bufferSize = 64 * 1024;
|
const int bufferSize = 64 * 1024;
|
||||||
byte[] buffer = new byte[bufferSize];
|
byte[] buffer = new byte[bufferSize];
|
||||||
MemoryStream temp = new MemoryStream();
|
|
||||||
int bIndex = 0;
|
int bIndex = 0;
|
||||||
|
|
||||||
// Store locally instead of performing func call for every block in map
|
// Store locally instead of performing func call for every block in map
|
||||||
@ -419,9 +403,10 @@ namespace MCGalaxy {
|
|||||||
convCPE[i] = Block.ConvertCPE((byte)i);
|
convCPE[i] = Block.ConvertCPE((byte)i);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (GZipStream compressor = new GZipStream(temp, CompressionMode.Compress, true)) {
|
using (GZipStream compressor = new GZipStream(dst, CompressionMode.Compress, true)) {
|
||||||
NetUtils.WriteI32(level.blocks.Length, buffer, 0);
|
NetUtils.WriteI32(level.blocks.Length, buffer, 0);
|
||||||
compressor.Write(buffer, 0, sizeof(int));
|
compressor.Write(buffer, 0, sizeof(int));
|
||||||
|
dst.length = level.blocks.Length;
|
||||||
|
|
||||||
// compress the map data in 64 kb chunks
|
// compress the map data in 64 kb chunks
|
||||||
if (hasCustomBlocks) {
|
if (hasCustomBlocks) {
|
||||||
@ -435,6 +420,7 @@ namespace MCGalaxy {
|
|||||||
|
|
||||||
bIndex++;
|
bIndex++;
|
||||||
if (bIndex == bufferSize) {
|
if (bIndex == bufferSize) {
|
||||||
|
dst.position = i;
|
||||||
compressor.Write(buffer, 0, bufferSize); bIndex = 0;
|
compressor.Write(buffer, 0, bufferSize); bIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,14 +436,13 @@ namespace MCGalaxy {
|
|||||||
|
|
||||||
bIndex++;
|
bIndex++;
|
||||||
if (bIndex == bufferSize) {
|
if (bIndex == bufferSize) {
|
||||||
|
dst.position = i;
|
||||||
compressor.Write(buffer, 0, bufferSize); bIndex = 0;
|
compressor.Write(buffer, 0, bufferSize); bIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bIndex > 0) compressor.Write(buffer, 0, bIndex);
|
if (bIndex > 0) compressor.Write(buffer, 0, bIndex);
|
||||||
}
|
}
|
||||||
usedLength = (int)temp.Length;
|
|
||||||
return temp.GetBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveOldLevelCustomBlocks(Level oldLevel) {
|
void RemoveOldLevelCustomBlocks(Level oldLevel) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user