using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text.RegularExpressions; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace CarFire { /// /// This class will be instantiated by the XNA Framework Content /// Pipeline to read cfmap files from binary .xnb format. /// public class MapReader : ContentTypeReader { public class ParserException : System.ApplicationException { public ParserException() { } public ParserException(string message) : base(message) { } public ParserException(string message, System.Exception inner) : base(message, inner) { } protected ParserException(SerializationInfo info, StreamingContext context) : base(info, context) { } } ContentReader mInput; int mLineNumber = 0; int mExpectedNumberOfLines; Map.Data mData; protected override Map Read(ContentReader input, Map existingInstance) { mInput = input; mExpectedNumberOfLines = mInput.ReadInt32(); ReadData(); return new Map(mData); } #region Private Reading Methods string ReadLine() { return mInput.ReadString(); } void ReadData() { mData = new Map.Data(); while (mLineNumber < mExpectedNumberOfLines) { string line = ReadLine(); mLineNumber++; while (line != null) { if (!IsLineSignificant(line)) break; string section = Parse.IniSectionHeader(line); if (section != null) { if (section == "metadata") { line = ReadMetadataSection(); } else if (section == "maptable") { line = ReadMapTableSection(); } else if (section.Length == 1) { line = ReadEntitySection(section[0]); } else { ThrowException("Unknown section", section); } } else { ThrowException("Unexpected text", line); } } } } string ReadMetadataSection() { while (mLineNumber < mExpectedNumberOfLines) { string line = ReadLine(); mLineNumber++; if (!IsLineSignificant(line)) continue; string[] pair = Parse.KeyValuePair(line); if (pair != null) { if (pair[0] == "type") { object type = Parse.Constant(pair[1]); if (type != null) { mData.Type = (Map.Type)type; } else { ThrowException("Invalid type", pair[1]); } } else if (pair[0] == "dimensions") { Point? dimensions = Parse.Coordinates(pair[1]); if (dimensions != null) { mData.Dimensions = dimensions.Value; if (mData.Dimensions.X <= 0 || mData.Dimensions.Y <= 0) { ThrowException("Invalid dimensions", pair[1]); } } else { ThrowException("Invalid value", pair[1]); } } else if (pair[0] == "tileset") { string tileset = Parse.String(pair[1]); if (tileset != null) { mData.Tileset = tileset; } else { ThrowException("Invalid tileset", pair[1]); } } else if (pair[0] == "numplayers") { int[] numPlayers = Parse.Range(pair[1]); if (numPlayers != null) { mData.MinNumPlayers = numPlayers[0]; mData.MaxNumPlayers = numPlayers[1]; if (mData.MinNumPlayers <= 0 || mData.MaxNumPlayers <= 0 || mData.MinNumPlayers > mData.MaxNumPlayers) { ThrowException("Invalid range", pair[1]); } } else { ThrowException("Invalid value", pair[1]); } } else if (pair[0] == "author") { string author = Parse.String(pair[1]); if (author != null) { mData.Author = author; } else { ThrowException("Invalid value", pair[1]); } } else if (pair[0] == "levelname") { string level = Parse.String(pair[1]); if (level != null) { mData.Name = level; } else { ThrowException("Invalid value", pair[1]); } } else { Console.WriteLine("Unimplemented key: " + pair[0]); } } else { return line; } } return null; } string ReadMapTableSection() { if (mData.Dimensions.X == 0 || mData.Dimensions.Y == 0) { ThrowException("Unexpected section", "You must define the map dimensions before this section."); } mData.Grid = new char[mData.Dimensions.X, mData.Dimensions.Y]; int y; for (y = 0; y < mData.Dimensions.Y && mLineNumber < mExpectedNumberOfLines; y++) { string line = ReadLine(); mLineNumber++; if (line.Length < mData.Dimensions.X) { ThrowException("Not enough characters", "Expecting " + mData.Dimensions.X + " characters."); } for (int x = 0; x < mData.Dimensions.X; x++) { mData.Grid[x, y] = line[x]; } } if (y < mData.Dimensions.Y) { ThrowException("Unexpected ", ""); } return null; } string ReadEntitySection(char entity) { while (mLineNumber < mExpectedNumberOfLines) { string line = ReadLine(); mLineNumber++; string[] pair = Parse.KeyValuePair(line); if (pair != null) { // TODO } else { return line; } } return null; } #endregion #region Private Methods bool IsLineSignificant(string line) { if (line.Length == 0 || Regex.IsMatch(line, @"^;|^\s*$")) return false; return true; } void ThrowException(string problem, string text) { throw new ParserException(problem + " on line " + mLineNumber + ": " + text); } #endregion } }