diff --git a/Commands/World/CmdImport.cs b/Commands/World/CmdImport.cs index 716eac380..cb98a1ad5 100644 --- a/Commands/World/CmdImport.cs +++ b/Commands/World/CmdImport.cs @@ -1,27 +1,28 @@ /* - Copyright 2011 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. -*/ + Copyright 2011 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 MCGalaxy.Levels.IO; -namespace MCGalaxy.Commands -{ - public sealed class CmdImport : Command - { +namespace MCGalaxy.Commands { + + public sealed class CmdImport : Command { + public override string name { get { return "import"; } } public override string shortcut { get { return ""; } } public override string type { get { return CommandTypes.World; } } @@ -30,29 +31,33 @@ namespace MCGalaxy.Commands public override void Use(Player p, string message) { if (message == "") { Help(p); return; } - string fileName = "extra/import/" + message + ".dat"; - - if (!Directory.Exists("extra/import")) - Directory.CreateDirectory("extra/import"); - if (!File.Exists(fileName)) { - Player.SendMessage(p, "Could not find .dat file"); - return; + string file = "extra/import/" + message; + if (!Directory.Exists("extra/import")) + Directory.CreateDirectory("extra/import"); + + if (File.Exists(file + ".dat")) { Import(p, file + ".dat", message, false); return; } + if (File.Exists(file + ".mcf")) { Import(p, file + ".mcf", message, true); return; } + Player.SendMessage(p, "No .dat or .mcf file with the given name was found in the imports directory."); + } + + void Import(Player p, string fileName, string message, bool mcf) { + using (FileStream fs = File.OpenRead(fileName)) { + try { + if (mcf) McfFile.Load(fs, message); + else DatFile.Load(fs, message); + } catch (Exception ex) { + Server.ErrorLog(ex); + Player.SendMessage(p, "The map conversion failed."); return; + } + Player.SendMessage(p, "Converted map!"); + Command.all.Find("load").Use(p, message); } - - using (FileStream fs = File.OpenRead(fileName)) { - if (ConvertDat.Load(fs, message) != null) { - Player.SendMessage(p, "Converted map!"); - Command.all.Find("load").Use(p, message); - } else { - Player.SendMessage(p, "The map conversion failed."); - } - } } public override void Help(Player p) { Player.SendMessage(p, "%T/import [name]"); - Player.SendMessage(p, "%HImports the .dat file with the given name."); - Player.SendMessage(p, "%HNote this command only loads .dat files from the /extra/import/ folder"); + Player.SendMessage(p, "%HImports the .dat or .mcf file with the given name."); + Player.SendMessage(p, "%HNote this command only loads .dat/.mcf files from the /extra/import/ folder"); } } } diff --git a/Levels/IO/ConvertDAT.cs b/Levels/IO/ConvertDAT.cs deleted file mode 100644 index 2a26682e7..000000000 --- a/Levels/IO/ConvertDAT.cs +++ /dev/null @@ -1,190 +0,0 @@ -// -// Authors: -// * Tyler Kennedy -// * Matvei Stefarov -// -// Copyright (c) 2010, Tyler Kennedy & Matvei Stefarov -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// * Neither the name of MCC nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -using System; -using System.IO; -using System.IO.Compression; -using System.Net; - -namespace MCGalaxy.Levels.IO { - - public static class ConvertDat { - - public static Level Load(Stream stream, string fileName) - { - byte[] temp = new byte[8]; - using (Level lvl = new Level(fileName, 0, 0, 0, "empty")) - { - try - { - stream.Seek(-4, SeekOrigin.End); - stream.Read(temp, 0, sizeof(int)); - stream.Seek(0, SeekOrigin.Begin); - int length = BitConverter.ToInt32(temp, 0); - byte[] data = new byte[length]; - using (GZipStream reader = new GZipStream(stream, CompressionMode.Decompress, true)) - reader.Read(data, 0, length); - - for (int i = 0; i < length - 1; i++) - { - if (data[i] == 0xAC && data[i + 1] == 0xED) - { - - // bypassing the header crap - int pointer = i + 6; - Array.Copy(data, pointer, temp, 0, sizeof(short)); - pointer += IPAddress.HostToNetworkOrder(BitConverter.ToInt16(temp, 0)); - pointer += 13; - - int headerEnd = 0; - // find the end of serialization listing - for (headerEnd = pointer; headerEnd < data.Length - 1; headerEnd++) - { - if (data[headerEnd] == 0x78 && data[headerEnd + 1] == 0x70) - { - headerEnd += 2; - break; - } - } - - // start parsing serialization listing - int offset = 0; - while (pointer < headerEnd) - { - if (data[pointer] == 'Z') offset++; - else if (data[pointer] == 'I' || data[pointer] == 'F') offset += 4; - else if (data[pointer] == 'J') offset += 8; - - pointer += 1; - Array.Copy(data, pointer, temp, 0, sizeof(short)); - short skip = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(temp, 0)); - pointer += 2; - - // look for relevant variables - Array.Copy(data, headerEnd + offset - 4, temp, 0, sizeof(int)); - if (MemCmp(data, pointer, "width")) - { - lvl.Width = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(temp, 0)); - } - else if (MemCmp(data, pointer, "depth")) - { - lvl.Height = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(temp, 0)); - } - else if (MemCmp(data, pointer, "height")) - { - lvl.Length = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(temp, 0)); - } - - pointer += skip; - } - lvl.width = lvl.Width; - lvl.depth = lvl.Height; - lvl.length = lvl.Length; lvl.height = lvl.Length; - - lvl.spawnx = (ushort)(lvl.Width / 1.3); - lvl.spawny = (ushort)(lvl.Height / 1.3); - lvl.spawnz = (ushort)(lvl.Length / 1.3); - - // find the start of the block array - bool foundBlockArray = false; - offset = Array.IndexOf(data, 0x00, headerEnd); - while (offset != -1 && offset < data.Length - 2) - { - if (data[offset] == 0x00 && data[offset + 1] == 0x78 && data[offset + 2] == 0x70) - { - foundBlockArray = true; - pointer = offset + 7; - } - offset = Array.IndexOf(data, 0x00, offset + 1); - } - - // copy the block array... or fail - if (foundBlockArray) - { - CopyBlocks(lvl, data, pointer); - lvl.Save(true); - } - else - { - throw new Exception("Could not locate block array."); - } - break; - } - } - } - catch (Exception ex) - { - Server.s.Log("Conversion failed"); - Server.ErrorLog(ex); - return null; - } - - return lvl; - } - } - - static bool MemCmp( byte[] data, int offset, string value ) { - for( int i = 0; i < value.Length; i++ ) { - if( offset + i >= data.Length || data[offset + i] != value[i] ) return false; - } - return true; - } - - static void CopyBlocks(Level lvl, byte[] source, int offset) { - byte[] blocks = new byte[lvl.Width * lvl.Height * lvl.Length]; - Array.Copy(source, offset, blocks, 0, blocks.Length); - - for (int i = 0; i < blocks.Length; i++) - { - if (blocks[i] >= 50) blocks[i] = 0; - switch (blocks[i]) - { - case Block.waterstill: - blocks[i] = Block.water; - break; - case Block.water: - blocks[i] = Block.waterstill; - break; - case Block.lava: - blocks[i] = Block.lavastill; - break; - case Block.lavastill: - blocks[i] = Block.lava; - break; - } - } - lvl.blocks = blocks; - } - } -} diff --git a/Levels/IO/DatFile.cs b/Levels/IO/DatFile.cs new file mode 100644 index 000000000..eb73502e3 --- /dev/null +++ b/Levels/IO/DatFile.cs @@ -0,0 +1,173 @@ +// +// Authors: +// * Tyler Kennedy +// * Matvei Stefarov +// +// Copyright (c) 2010, Tyler Kennedy & Matvei Stefarov +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// * Neither the name of MCC nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +using System; +using System.IO; +using System.IO.Compression; +using System.Net; + +namespace MCGalaxy.Levels.IO { + + public static class DatFile { + + public static Level Load(Stream stream, string name) + { + byte[] temp = new byte[8]; + using (Level lvl = new Level(name, 0, 0, 0, "empty")) + { + stream.Seek(-4, SeekOrigin.End); + stream.Read(temp, 0, sizeof(int)); + stream.Seek(0, SeekOrigin.Begin); + int length = BitConverter.ToInt32(temp, 0); + byte[] data = new byte[length]; + using (GZipStream reader = new GZipStream(stream, CompressionMode.Decompress, true)) + reader.Read(data, 0, length); + + for (int i = 0; i < length - 1; i++) + { + if (data[i] == 0xAC && data[i + 1] == 0xED) + { + + // bypassing the header crap + int pointer = i + 6; + Array.Copy(data, pointer, temp, 0, sizeof(short)); + pointer += IPAddress.HostToNetworkOrder(BitConverter.ToInt16(temp, 0)); + pointer += 13; + + int headerEnd = 0; + // find the end of serialization listing + for (headerEnd = pointer; headerEnd < data.Length - 1; headerEnd++) + { + if (data[headerEnd] == 0x78 && data[headerEnd + 1] == 0x70) + { + headerEnd += 2; + break; + } + } + + // start parsing serialization listing + int offset = 0; + while (pointer < headerEnd) + { + if (data[pointer] == 'Z') offset++; + else if (data[pointer] == 'I' || data[pointer] == 'F') offset += 4; + else if (data[pointer] == 'J') offset += 8; + + pointer += 1; + Array.Copy(data, pointer, temp, 0, sizeof(short)); + short skip = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(temp, 0)); + pointer += 2; + + // look for relevant variables + Array.Copy(data, headerEnd + offset - 4, temp, 0, sizeof(int)); + if (MemCmp(data, pointer, "width")) + { + lvl.Width = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(temp, 0)); + } + else if (MemCmp(data, pointer, "depth")) + { + lvl.Height = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(temp, 0)); + } + else if (MemCmp(data, pointer, "height")) + { + lvl.Length = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(temp, 0)); + } + + pointer += skip; + } + + lvl.spawnx = (ushort)(lvl.Width / 1.3); + lvl.spawny = (ushort)(lvl.Height / 1.3); + lvl.spawnz = (ushort)(lvl.Length / 1.3); + + // find the start of the block array + bool foundBlockArray = false; + offset = Array.IndexOf(data, 0x00, headerEnd); + while (offset != -1 && offset < data.Length - 2) + { + if (data[offset] == 0x00 && data[offset + 1] == 0x78 && data[offset + 2] == 0x70) + { + foundBlockArray = true; + pointer = offset + 7; + } + offset = Array.IndexOf(data, 0x00, offset + 1); + } + + // copy the block array... or fail + if (foundBlockArray) { + CopyBlocks(lvl, data, pointer); + lvl.Save(true); + } else { + throw new InvalidDataException("Could not locate block array."); + } + break; + } + } + return lvl; + } + } + + static bool MemCmp( byte[] data, int offset, string value ) { + for( int i = 0; i < value.Length; i++ ) { + if( offset + i >= data.Length || data[offset + i] != value[i] ) return false; + } + return true; + } + + static void CopyBlocks(Level lvl, byte[] source, int offset) { + byte[] blocks = new byte[lvl.Width * lvl.Height * lvl.Length]; + Array.Copy(source, offset, blocks, 0, blocks.Length); + + for (int i = 0; i < blocks.Length; i++) + { + if (blocks[i] >= 50) blocks[i] = 0; + switch (blocks[i]) + { + case Block.waterstill: + blocks[i] = Block.water; + break; + case Block.water: + blocks[i] = Block.waterstill; + break; + case Block.lava: + blocks[i] = Block.lavastill; + break; + case Block.lavastill: + blocks[i] = Block.lava; + break; + } + } + lvl.blocks = blocks; + } + } +} diff --git a/Levels/IO/LvlFile.cs b/Levels/IO/LvlFile.cs index 65f940d52..a2ae6c4e1 100644 --- a/Levels/IO/LvlFile.cs +++ b/Levels/IO/LvlFile.cs @@ -18,7 +18,6 @@ using System; using System.IO; using System.IO.Compression; -using System.Linq; namespace MCGalaxy.Levels.IO { diff --git a/Levels/IO/McfFile.cs b/Levels/IO/McfFile.cs new file mode 100644 index 000000000..ddfb2093e --- /dev/null +++ b/Levels/IO/McfFile.cs @@ -0,0 +1,62 @@ +/* +Copyright (C) 2010-2013 David Mitchell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +using System; +using System.IO; +using System.IO.Compression; + +namespace MCGalaxy.Levels.IO { + + public static class McfFile { + + public static Level Load(Stream stream, string name) { + GZipStream gs = new GZipStream(stream, CompressionMode.Decompress); + byte[] ver = new byte[2]; + gs.Read(ver, 0, ver.Length); + + if (BitConverter.ToUInt16(ver, 0) != 1874) + throw new InvalidDataException(".mcf files must have a version of 1874"); + + byte[] header = new byte[16]; + gs.Read(header, 0, header.Length); + ushort width = BitConverter.ToUInt16(header, 0); + ushort length = BitConverter.ToUInt16(header, 2); + ushort height = BitConverter.ToUInt16(header, 4); + + Level lvl = new Level(name, width, height, length, "full_empty"); + lvl.permissionbuild = (LevelPermission)30; + lvl.spawnx = BitConverter.ToUInt16(header, 6); + lvl.spawnz = BitConverter.ToUInt16(header, 8); + lvl.spawny = BitConverter.ToUInt16(header, 10); + lvl.rotx = header[12]; + lvl.roty = header[13]; + + byte[] blocks = new byte[2 * lvl.blocks.Length]; + gs.Read(blocks, 0, blocks.Length); + for (int i = 0; i < blocks.Length / 2; ++i) + lvl.blocks[i] = blocks[i * 2]; + + gs.Close(); + lvl.Save(true); + return lvl; + } + } +} \ No newline at end of file diff --git a/MCGalaxy_.csproj b/MCGalaxy_.csproj index e440bb46e..49779d535 100644 --- a/MCGalaxy_.csproj +++ b/MCGalaxy_.csproj @@ -411,9 +411,10 @@ - + +