/// <summary> /// Uses polymorphic features of the IDataType interface to save the different data types differently /// Headers for all types of files match, save for the first 3 bytes, which use the file extension to /// save the proper string. /// </summary> /// <param name="pubVersion">Version of the pub file to save. For Ethan's client, items should be 1, otherwise, this should be 0 (for now)</param> /// <param name="error">ref parameter that provides the Exception.Message string on an error condition</param> /// <returns>True if successful, false on failure. Use the 'error' parameter to check error message</returns> public bool Save(int pubVersion, ref string error) { try { using (FileStream sw = File.Create(FilePath)) //throw exceptions on error { if (FilePath.Length <= 4 || !FilePath.Contains('.')) { throw new ArgumentException("The filename of the data file must have a 3 letter extension. Use EIF, ENF, ESF, or ECF."); } //get the extension to write as the first 3 bytes byte[] extension = Encoding.ASCII.GetBytes(FilePath.ToUpper().Substring(FilePath.LastIndexOf('.') + 1)); if (extension.Length != 3) { throw new ArgumentException("The filename of the data file must have a 3 letter extension. Use EIF, ENF, ESF, or ECF."); } //allocate the data array for all the data to be saved byte[] allData; //write the file to memory first using (MemoryStream mem = new MemoryStream()) { mem.Write(extension, 0, 3); //E[I|N|S|C]F at beginning mem.Write(Packet.EncodeNumber(Rid, 4), 0, 4); //rid mem.Write(Packet.EncodeNumber(Data.Count, 2), 0, 2); //len Version = pubVersion; mem.WriteByte(Packet.EncodeNumber(Version, 1)[0]); //new version check for (int i = 1; i < Data.Count; ++i) { byte[] toWrite = Data[i].SerializeToByteArray(); mem.Write(toWrite, 0, toWrite.Length); } allData = mem.ToArray(); //get all data bytes } //write the data to the stream and overwrite whatever the rid is with the CRC CRC32 crc = new CRC32(); uint newRid = crc.Check(allData, 7, (uint)allData.Length - 7); Rid = (int)newRid; sw.Write(allData, 0, allData.Length); sw.Seek(3, SeekOrigin.Begin); //skip first 3 bytes sw.Write(Packet.EncodeNumber(Rid, 4), 0, 4); //overwrite the 4 RID (revision ID) bytes } } catch (Exception ex) { error = ex.Message; return(false); } error = "none"; return(true); }
public bool Save(string filename, bool saveAs = false) { if (isSaved && !saveAs) { return(true); } // Initially, write to a memory stream so we can CRC the data uint crcVal = 0; byte[] allBytes = null; using (MemoryStream ms = new MemoryStream()) { ms.WriteInt(Const.MAGIC_NUMBER); // Map info ms.WriteInt((int)MapField.MapInfo); ms.WriteInt(w); ms.WriteInt(h); ms.WriteInt((int)Type); ms.WriteString(MapName); ms.WriteInt(Warp); ms.WriteInt(PlayerSpawn.X); ms.WriteInt(PlayerSpawn.Y); ms.WriteInt(layers.Length); // Write map layers foreach (SortedList <string, Tile> layer in this.layers) { ms.WriteInt((int)MapField.MapLayer); // Write number of tiles ms.WriteInt(layer.Count); foreach (Tile t in layer.Values) { if (t is AnimatedTile) { AnimatedTile at = (AnimatedTile)t; ms.WriteInt((int)TileType.Animated); ms.WriteInt(at.X); ms.WriteInt(at.Y); ms.WriteInt(at.Graphic); } else if (t is GraphicTile) { GraphicTile gt = (GraphicTile)t; ms.WriteInt((int)TileType.Graphic); ms.WriteInt(gt.X); ms.WriteInt(gt.Y); ms.WriteInt(gt.Graphic); } else if (t is SpecialTile) { SpecialTile st = (SpecialTile)t; ms.WriteInt((int)TileType.Special); ms.WriteInt(st.X); ms.WriteInt(st.Y); ms.WriteInt((int)st.Type); switch (st.Type) { case SpecialTileSpec.CAVE: case SpecialTileSpec.GRASS: case SpecialTileSpec.WATER: ms.WriteInt((int)st.SpawnID); break; case SpecialTileSpec.WARP: ms.WriteInt(st.WarpMap); ms.WriteInt(st.WarpX); ms.WriteInt(st.WarpY); ms.WriteInt((int)st.WarpAnim); break; } } } } // Write spawns int numSpawnsWritten = 0; foreach (Spawn sp in Spawns) { // If this happens, we shouldn't write any more. Might as well stop now. if (numSpawnsWritten > this.Spawns.Count) { break; } ms.WriteInt((int)MapField.SpawnInfo); ms.WriteInt(sp.SpawnID); ms.WriteString(sp.Name); ms.WriteInt(sp.Spawns.Count); int numPairsWritten = 0; foreach (KeyValuePair <int, int> pair in sp.Spawns) { // Same error condition as before if (numPairsWritten > sp.Spawns.Count) { break; } ms.WriteInt(pair.Key); ms.WriteInt(pair.Value); numPairsWritten++; } numSpawnsWritten++; } allBytes = new byte[ms.Length]; ms.Seek(0, SeekOrigin.Begin); ms.Read(allBytes, 0, allBytes.Length); CRC32 crc = new CRC32(); crcVal = crc.Check(allBytes); } using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(filename))) { bw.Write(allBytes); bw.Write(ByteConverter.ToBytes(crcVal)); } isSaved = true; fileName = filename; return(isSaved); }
/// <summary> /// Uses polymorphic features of the IDataType interface to save the different data types differently /// Headers for all types of files match, save for the first 3 bytes, which use the file extension to /// save the proper string. /// </summary> /// <param name="pubVersion">Version of the pub file to save. For Ethan's client, items should be 1, otherwise, this should be 0 (for now)</param> /// <param name="error">ref parameter that provides the Exception.Message string on an error condition</param> /// <returns>True if successful, false on failure. Use the 'error' parameter to check error message</returns> public bool Save(int pubVersion, ref string error) { try { using (FileStream sw = File.Create(FilePath)) //throw exceptions on error { if (FilePath.Length <= 4 || !FilePath.Contains('.')) { throw new ArgumentException("The filename of the data file must have a 3 letter extension. Use EIF, ENF, ESF, or ECF."); } //get the extension to write as the first 3 bytes byte[] extension = Encoding.ASCII.GetBytes(FilePath.ToUpper().Substring(FilePath.LastIndexOf('.') + 1)); if (extension.Length != 3) { throw new ArgumentException("The filename of the data file must have a 3 letter extension. Use EIF, ENF, ESF, or ECF."); } //allocate the data array for all the data to be saved //this is done based on the type of the Data items byte[] allData; if (Data.Count > 0) { if (Data[0] is ItemRecord) { allData = new byte[10 + ItemFile.DATA_SIZE * Data.Count]; } else if (Data[0] is NPCRecord) { allData = new byte[10 + NPCFile.DATA_SIZE * Data.Count]; } else if (Data[0] is SpellRecord) { allData = new byte[10 + SpellFile.DATA_SIZE * Data.Count]; } else if (Data[0] is ClassRecord) { allData = new byte[10 + ClassFile.DATA_SIZE * Data.Count]; } else { throw new ArgumentException("The internal data container has records of invalid type. Memory is corrupted."); } } else { throw new IndexOutOfRangeException("There are no data items to save!"); } //write the file to memory first (wrapper around allData byte array) using (MemoryStream mem = new MemoryStream(allData)) { mem.Write(extension, 0, 3); //E[I|N|S|C]F at beginning mem.Write(Packet.EncodeNumber(Rid, 4), 0, 4); //rid mem.Write(Packet.EncodeNumber(Data.Count, 2), 0, 2); //len Version = pubVersion; mem.WriteByte(Packet.EncodeNumber(Version, 1)[0]); //new version check for (int i = 1; i < Data.Count; ++i) { byte[] toWrite = Data[i].SerializeToByteArray(); mem.Write(toWrite, 0, toWrite.Length); } } //write the data to the stream and overwrite whatever the rid is with the CRC CRC32 crc = new CRC32(); uint newRid = crc.Check(allData, 7, (uint)allData.Length - 7); Rid = (int)newRid; sw.Write(allData, 0, allData.Length); sw.Seek(4, SeekOrigin.Begin); sw.Write(Packet.EncodeNumber(Rid, 4), 0, 4); } } catch (Exception ex) { error = ex.Message; return(false); } error = "none"; return(true); }
public bool LoadFromStream(Stream s) { isLoaded = false; byte[] all; using (var memoryStream = new MemoryStream()) { s.CopyTo(memoryStream); all = memoryStream.ToArray(); } CRC32 crc = new CRC32(); uint crcVal = crc.Check(all, 0, (uint)all.Length - 4); //crc everything except the value of the crc s.Seek(-sizeof(int), SeekOrigin.End); //last four bytes (int) is CRC value uint fileVal = (uint)s.ReadInt(); if (crcVal != fileVal) { return(isLoaded); } s.Seek(0, SeekOrigin.Begin); if (s.ReadInt() != Const.MAGIC_NUMBER) { return(isLoaded); } spawns = new List <Spawn>(); int loadedLayers = 0; while (s.Position < s.Length - 4) { switch ((MapField)s.ReadInt()) { case MapField.MapInfo: w = s.ReadInt(); h = s.ReadInt(); Type = (MapType)s.ReadInt(); mapname = s.ReadString(); Warp = s.ReadInt(); PlayerSpawn = new Microsoft.Xna.Framework.Point(s.ReadInt(), s.ReadInt()); int numLayers = s.ReadInt(); if (numLayers != this.layers.Length) { throw new Exception("Invalid number of layers!"); } break; case MapField.MapLayer: int numTiles = s.ReadInt(); var newLayer = layers[loadedLayers] = new SortedList <string, Tile>(numTiles); for (int i = 0; i < numTiles; i++) { Tile toAdd = null; LAYERS layer = LAYERS.Graphic; switch ((TileType)s.ReadInt()) { case TileType.Animated: toAdd = new AnimatedTile(s.ReadInt(), s.ReadInt(), s.ReadInt()); layer = LAYERS.Graphic; break; case TileType.Graphic: toAdd = new GraphicTile(s.ReadInt(), s.ReadInt(), s.ReadInt()); break; case TileType.Special: SpecialTile st = new SpecialTile(s.ReadInt(), s.ReadInt()); SpecialTileSpec tt = (SpecialTileSpec)s.ReadInt(); object[] param = null; switch (tt) { case SpecialTileSpec.CAVE: case SpecialTileSpec.GRASS: case SpecialTileSpec.WATER: param = new object[] { s.ReadInt() }; break; case SpecialTileSpec.WARP: param = new object[] { s.ReadInt(), s.ReadInt(), s.ReadInt(), (WarpAnim)s.ReadInt() }; break; } st.SetType(tt, param); break; } if (toAdd != null) { AddTile(toAdd.X, toAdd.Y, layer, toAdd); } } layers[loadedLayers++] = newLayer; break; case MapField.SpawnInfo: Spawn sp = new Spawn(s.ReadInt(), s.ReadString()); int numPairs = s.ReadInt(); for (int i = 0; i < numPairs; i++) { sp.AddSpawnPair(s.ReadInt(), s.ReadInt()); } break; } } // Make sure we don't have any null layers (they cause problems later) for (int i = 0; i < layers.Length; i++) { if (layers[i] == null) { layers[i] = new SortedList <string, Tile>(); } } fileName = ""; isLoaded = true; isSaved = true; return(isLoaded); }
/// <summary> /// Uses polymorphic features of the IDataType interface to save the different data types differently /// Headers for all types of files match, save for the first 3 bytes, which use the file extension to /// save the proper string. /// </summary> /// <param name="pubVersion">Version of the pub file to save. For Ethan's client, items should be 1, otherwise, this should be 0 (for now)</param> /// <param name="error">ref parameter that provides the Exception.Message string on an error condition</param> /// <returns>True if successful, false on failure. Use the 'error' parameter to check error message</returns> public bool Save(int pubVersion, out string error) { try { using (FileStream sw = File.Create(FilePath)) //throw exceptions on error { if (FilePath.Length <= 4 || !FilePath.Contains('.')) throw new ArgumentException("The filename of the data file must have a 3 letter extension. Use EIF, ENF, ESF, or ECF."); //get the extension to write as the first 3 bytes byte[] extension = Encoding.ASCII.GetBytes(FilePath.ToUpper().Substring(FilePath.LastIndexOf('.') + 1)); if (extension.Length != 3) throw new ArgumentException("The filename of the data file must have a 3 letter extension. Use EIF, ENF, ESF, or ECF."); //allocate the data array for all the data to be saved byte[] allData; //write the file to memory first using (MemoryStream mem = new MemoryStream()) { mem.Write(extension, 0, 3); //E[I|N|S|C]F at beginning mem.Write(Packet.EncodeNumber(Rid, 4), 0, 4); //rid mem.Write(Packet.EncodeNumber(Data.Count, 2), 0, 2); //len Version = pubVersion; mem.WriteByte(Packet.EncodeNumber(Version, 1)[0]); //new version check for (int i = 1; i < Data.Count; ++i) { byte[] toWrite = Data[i].SerializeToByteArray(); mem.Write(toWrite, 0, toWrite.Length); } allData = mem.ToArray(); //get all data bytes } //write the data to the stream and overwrite whatever the rid is with the CRC CRC32 crc = new CRC32(); uint newRid = crc.Check(allData, 7, (uint)allData.Length - 7); Rid = (int)newRid; sw.Write(allData, 0, allData.Length); sw.Seek(3, SeekOrigin.Begin); //skip first 3 bytes sw.Write(Packet.EncodeNumber(Rid, 4), 0, 4); //overwrite the 4 RID (revision ID) bytes } } catch (Exception ex) { error = ex.Message; return false; } error = "none"; return true; }