Implement FastMap CPE extension

This commit is contained in:
UnknownShadow200 2018-04-01 13:27:15 +10:00
parent d140333461
commit 3e2f072666
9 changed files with 64 additions and 41 deletions

View File

@ -53,8 +53,8 @@ namespace MCGalaxy.Commands.Fun {
public override void Help(Player p) {
Player.Message(p, "%T/Queue zombie [name]");
Player.Message(p, "%HNext round [name] will be infected/start zombie");
Player.Message(p, "%T/Queue level [name]");
Player.Message(p, "%HNext round [name] will be the level used");
Player.Message(p, "%T/Queue level [map]");
Player.Message(p, "%HNext round [map] will be the level used");
}
}
}

View File

@ -54,8 +54,8 @@ namespace MCGalaxy.Commands.World {
public override void Help(Player p) {
Player.Message(p, "%T/Main");
Player.Message(p, "%HSends you to the main level.");
Player.Message(p, "%T/Main [level]");
Player.Message(p, "%HSets the main level to that level.");
Player.Message(p, "%T/Main [map]");
Player.Message(p, "%HSets the main level to that map.");
}
}
}

View File

@ -132,7 +132,7 @@ namespace MCGalaxy.Commands.World {
static string GetBool(bool value) { return value ? "&aON" : "&cOFF"; }
public override void Help(Player p) {
Player.Message(p, "%T/Map [level] [option] <value> %H- Sets [option] on [level]");
Player.Message(p, "%T/Map [map] [option] <value> %H- Sets [option] on that map");
Player.Message(p, "%HPossible options: %S{0}", LevelOptions.Options.Keys.Join());
Player.Message(p, "%HUse %T/Help map [option] %Hto see description for that option.");
}

View File

@ -56,7 +56,7 @@ namespace MCGalaxy.Commands.World {
string map = args.Length == 1 ? p.level.name : Matcher.FindMaps(p, args[0]);
if (map == null) return;
Level lvl;
LevelConfig cfg = LevelInfo.GetConfig(map, out lvl);
LevelConfig cfg = LevelInfo.GetConfig(map, out lvl);
int offset = args.Length == 1 ? 0 : 1;
AccessController access;
@ -94,13 +94,13 @@ namespace MCGalaxy.Commands.World {
}
protected void ShowHelp(Player p, string action, string action2) {
Player.Message(p, "%T/{0} [level] [rank]", name);
Player.Message(p, "%HSets the lowest rank able to {0} the given level.", action);
Player.Message(p, "%T/{0} -max [Level] [Rank]", name);
Player.Message(p, "%HSets the highest rank able to {0} the given level.", action);
Player.Message(p, "%T/{0} [level] +[name]", name);
Player.Message(p, "%T/{0} [map] [rank]", name);
Player.Message(p, "%HSets the lowest rank able to {0} the given map.", action);
Player.Message(p, "%T/{0} -max [map] [Rank]", name);
Player.Message(p, "%HSets the highest rank able to {0} the given map.", action);
Player.Message(p, "%T/{0} [map] +[name]", name);
Player.Message(p, "%HAllows [name] to {0}, even if their rank cannot.", action2);
Player.Message(p, "%T/{0} [level] -[name]", name);
Player.Message(p, "%T/{0} [map] -[name]", name);
Player.Message(p, "%HPrevents [name] from {0}ing, even if their rank can.", action2);
}
}

View File

@ -75,7 +75,7 @@ namespace MCGalaxy.Eco {
}
protected internal override void OnStoreCommand(Player p) {
Player.Message(p, "%T/Buy {0} [map name]", Name);
Player.Message(p, "%T/Buy {0} [map]", Name);
OutputItemInfo(p);
Player.Message(p, "The map used for the next round of " +
"zombie survival will be the given map.");

View File

@ -46,7 +46,13 @@ namespace MCGalaxy.Network {
public static byte[] Ping() { return new byte[] { Opcode.Ping }; }
public static byte[] LevelInitalise() { return new byte[] { Opcode.LevelInitialise }; }
public static byte[] LevelInitalise() { return new byte[] { Opcode.LevelInitialise }; }
public static byte[] LevelInitaliseExt(int volume) {
byte[] buffer = new byte[5];
buffer[0] = Opcode.LevelInitialise;
NetUtils.WriteI32(volume, buffer, 1);
return buffer;
}
public static byte[] LevelFinalise(ushort width, ushort height, ushort length) {
byte[] buffer = new byte[7];
@ -230,7 +236,7 @@ namespace MCGalaxy.Network {
}
public static byte[] BlockPermission(BlockID raw, bool place, bool delete, bool extBlocks) {
byte[] buffer = new byte[extBlocks ? 5 : 4];
byte[] buffer = new byte[extBlocks ? 5 : 4];
WriteBlockPermission(raw, place, delete, extBlocks, buffer, 0);
return buffer;
}

View File

@ -193,8 +193,13 @@ namespace MCGalaxy {
AccessResult access = level.BuildAccess.Check(this);
AllowBuild = access == AccessResult.Whitelisted || access == AccessResult.Allowed;
try {
Send(Packet.LevelInitalise());
try {
if (Supports(CpeExt.FastMap)) {
int volume = level.blocks.Length;
Send(Packet.LevelInitaliseExt(volume));
} else {
Send(Packet.LevelInitalise());
}
if (hasBlockDefs) {
if (oldLevel != null && oldLevel != level) {
@ -207,8 +212,9 @@ namespace MCGalaxy {
}
}
using (LevelChunkStream s = new LevelChunkStream(this))
using (LevelChunkStream s = new LevelChunkStream(this)) {
LevelChunkStream.CompressMap(this, s);
}
// Force players to read the MOTD (clamped to 3 seconds at most)
if (level.Config.LoadDelay > 0)

View File

@ -36,7 +36,8 @@ namespace MCGalaxy.Network {
public override long Seek(long offset, SeekOrigin origin) { throw ex; }
public override void SetLength(long length) { throw ex; }
internal int index, position, length;
int index;
byte chunkValue;
Player p;
byte[] data = new byte[chunkSize + 4];
const int chunkSize = 1024;
@ -77,12 +78,24 @@ namespace MCGalaxy.Network {
void WritePacket() {
data[0] = Opcode.LevelDataChunk;
NetUtils.WriteU16((ushort)index, data, 1);
data[1027] = (byte)(100 * (float)position / length);
data[1027] = chunkValue;
p.Send(data);
index = 0;
}
static Stream CompressMapHeader(Player player, int volume, LevelChunkStream dst) {
Stream stream = null;
if (player.Supports(CpeExt.FastMap)) {
stream = new DeflateStream(dst, CompressionMode.Compress, true);
} else {
stream = new GZipStream(dst, CompressionMode.Compress, true);
byte[] buffer = new byte[4]; NetUtils.WriteI32(volume, buffer, 0);
stream.Write(buffer, 0, sizeof(int));
}
return stream;
}
public unsafe static void CompressMap(Player p, LevelChunkStream dst) {
const int bufferSize = 64 * 1024;
byte[] buffer = new byte[bufferSize];
@ -109,7 +122,7 @@ namespace MCGalaxy.Network {
// Players with block defs don't need fallbacks for first 256 blocks
if (block < Block.Count && p.hasBlockDefs) { conv[b] = (byte)block; continue; }
// Use custom block fallback, if possible
BlockDefinition def = p.level.CustomBlockDefs[block];
if (def == null) {
@ -128,12 +141,10 @@ namespace MCGalaxy.Network {
Level lvl = p.level;
bool hasBlockDefs = p.hasBlockDefs;
using (GZipStream gs = new GZipStream(dst, CompressionMode.Compress, true)) {
byte[] blocks = lvl.blocks;
NetUtils.WriteI32(blocks.Length, buffer, 0);
gs.Write(buffer, 0, sizeof(int));
dst.length = blocks.Length;
byte[] blocks = lvl.blocks;
float progScale = 100.0f / blocks.Length;
using (Stream stream = CompressMapHeader(p, blocks.Length, dst)) {
// compress the map data in 64 kb chunks
#if TEN_BIT_BLOCKS
if (p.hasExtBlocks) {
@ -155,8 +166,8 @@ namespace MCGalaxy.Network {
bIndex += 2;
if (bIndex == bufferSize) {
dst.position = i;
gs.Write(buffer, 0, bufferSize); bIndex = 0;
dst.chunkValue = (byte)(i * progScale);
stream.Write(buffer, 0, bufferSize); bIndex = 0;
}
}
} else if (p.hasBlockDefs) {
@ -174,8 +185,8 @@ namespace MCGalaxy.Network {
bIndex++;
if (bIndex == bufferSize) {
dst.position = i;
gs.Write(buffer, 0, bufferSize); bIndex = 0;
dst.chunkValue = (byte)(i * progScale);
stream.Write(buffer, 0, bufferSize); bIndex = 0;
}
}
} else {
@ -192,8 +203,8 @@ namespace MCGalaxy.Network {
bIndex++;
if (bIndex == bufferSize) {
dst.position = i;
gs.Write(buffer, 0, bufferSize); bIndex = 0;
dst.chunkValue = (byte)(i * progScale);
stream.Write(buffer, 0, bufferSize); bIndex = 0;
}
}
}
@ -209,8 +220,8 @@ namespace MCGalaxy.Network {
bIndex++;
if (bIndex == bufferSize) {
dst.position = i;
gs.Write(buffer, 0, bufferSize); bIndex = 0;
dst.chunkValue = (byte)(i * progScale);
stream.Write(buffer, 0, bufferSize); bIndex = 0;
}
}
} else {
@ -223,15 +234,14 @@ namespace MCGalaxy.Network {
bIndex++;
if (bIndex == bufferSize) {
dst.position = i;
gs.Write(buffer, 0, bufferSize); bIndex = 0;
dst.chunkValue = (byte)(i * progScale);
stream.Write(buffer, 0, bufferSize); bIndex = 0;
}
}
}
#endif
if (bIndex > 0) gs.Write(buffer, 0, bIndex);
if (bIndex > 0) stream.Write(buffer, 0, bIndex);
}
}
}

View File

@ -48,7 +48,7 @@ namespace MCGalaxy {
new ExtEntry(CpeExt.EnvMapAspect), new ExtEntry(CpeExt.PlayerClick),
new ExtEntry(CpeExt.EntityProperty), new ExtEntry(CpeExt.ExtEntityPositions),
new ExtEntry(CpeExt.TwoWayPing), new ExtEntry(CpeExt.InventoryOrder),
new ExtEntry(CpeExt.InstantMOTD),
new ExtEntry(CpeExt.InstantMOTD), new ExtEntry(CpeExt.FastMap),
#if TEN_BIT_BLOCKS
new ExtEntry(CpeExt.ExtBlocks),
#endif
@ -204,6 +204,7 @@ namespace MCGalaxy {
public const string TwoWayPing = "TwoWayPing";
public const string InventoryOrder = "InventoryOrder";
public const string InstantMOTD = "InstantMOTD";
public const string FastMap = "FastMap";
public const string ExtBlocks = "ExtBlocks";
}