X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fcarfire;a=blobdiff_plain;f=CarFire%2FCarFire%2FCarFire%2FMapReader.cs;h=fbae4df99f8b7988a1e2f9f7069c7062c470af24;hp=35089ba6531d7345f15e0a164790f01f81c3d322;hb=1393586d1e5639ac8f1e9fc8183644050dd54165;hpb=2eb9216eac3321adc2f897068396e7fb1f126089 diff --git a/CarFire/CarFire/CarFire/MapReader.cs b/CarFire/CarFire/CarFire/MapReader.cs index 35089ba..fbae4df 100644 --- a/CarFire/CarFire/CarFire/MapReader.cs +++ b/CarFire/CarFire/CarFire/MapReader.cs @@ -2,7 +2,6 @@ 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; @@ -15,61 +14,51 @@ namespace CarFire /// public class MapReader : ContentTypeReader { + #region Public Exceptions + + /// + /// This exception is thrown during the loading of a map if any + /// part of the map file is inconsistent with the expected format + /// and order. + /// public class ParserException : System.ApplicationException { - public ParserException() - { - } + public ParserException() {} public ParserException(string message) : - base(message) - { - } + base(message) {} public ParserException(string message, System.Exception inner) : - base(message, inner) - { - } + base(message, inner) {} protected ParserException(SerializationInfo info, StreamingContext context) : - base(info, context) - { - } + base(info, context) {} } - ContentReader mInput; - int mLineNumber = 0; - int mExpectedNumberOfLines; + #endregion - Map.Data mData; + #region Protected Methods protected override Map Read(ContentReader input, Map existingInstance) { - mInput = input; - mExpectedNumberOfLines = mInput.ReadInt32(); - - ReadData(); - - return new Map(mData); + mInput = new LineReader(input); + ReadSectionHeaders(); + return new Map(mMetadata, mGrid, mEntities); } + #endregion - #region Private Reading Methods - - string ReadLine() - { - return mInput.ReadString(); - } - void ReadData() + #region Private Methods + + void ReadSectionHeaders() { - mData = new Map.Data(); + mMetadata = new Map.Metadata(); - while (mLineNumber < mExpectedNumberOfLines) + while (!mInput.End) { - string line = ReadLine(); - mLineNumber++; + string line = mInput.ReadLine(); while (line != null) { @@ -92,12 +81,12 @@ namespace CarFire } else { - ThrowException("Unknown section", section); + throw new ParserException("Unexpected section on line " + mInput.LineNumber + ": " + section); } } else { - ThrowException("Unexpected text", line); + throw new ParserException("Unexpected text on line " + mInput.LineNumber + ": " + line); } } } @@ -105,11 +94,9 @@ namespace CarFire string ReadMetadataSection() { - while (mLineNumber < mExpectedNumberOfLines) + while (!mInput.End) { - string line = ReadLine(); - mLineNumber++; - + string line = mInput.ReadLine(); if (!IsLineSignificant(line)) continue; string[] pair = Parse.KeyValuePair(line); @@ -117,14 +104,14 @@ namespace CarFire { if (pair[0] == "type") { - object type = Parse.Constant(pair[1]); - if (type != null) + Map.Type type = Parse.Constant(pair[1]); + if (type != default(Map.Type)) { - mData.Type = (Map.Type)type; + mMetadata.Type = type; } else { - ThrowException("Invalid type", pair[1]); + throw new ParserException("Unexpected type on line " + mInput.LineNumber + ": " + pair[1]); } } else if (pair[0] == "dimensions") @@ -132,15 +119,16 @@ namespace CarFire Point? dimensions = Parse.Coordinates(pair[1]); if (dimensions != null) { - mData.Dimensions = dimensions.Value; - if (mData.Dimensions.X <= 0 || mData.Dimensions.Y <= 0) + mMetadata.GridWidth = dimensions.Value.X; + mMetadata.GridHeight = dimensions.Value.Y; + if (mMetadata.GridWidth <= 0 || mMetadata.GridHeight <= 0) { - ThrowException("Invalid dimensions", pair[1]); + throw new ParserException("Invalid dimensions on line " + mInput.LineNumber + ": " + pair[1]); } } else { - ThrowException("Invalid value", pair[1]); + throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]); } } else if (pair[0] == "tileset") @@ -148,29 +136,46 @@ namespace CarFire string tileset = Parse.String(pair[1]); if (tileset != null) { - mData.Tileset = tileset; + mMetadata.Tileset = tileset; } else { - ThrowException("Invalid tileset", pair[1]); + throw new ParserException("Unexpected tileset on line " + mInput.LineNumber + ": " + pair[1]); } } else if (pair[0] == "numplayers") { - int[] numPlayers = Parse.Range(pair[1]); - if (numPlayers != null) + string[] list = Parse.List(pair[1]); + if (list != null) { - mData.MinNumPlayers = numPlayers[0]; - mData.MaxNumPlayers = numPlayers[1]; - if (mData.MinNumPlayers <= 0 || mData.MaxNumPlayers <= 0 || - mData.MinNumPlayers > mData.MaxNumPlayers) + foreach (string atom in list) + { + int[] range = Parse.Range(atom); + if (range != null) + { + for (int i = range[0]; i <= range[1]; i++) + { + mMetadata.NumPlayers.Add(i); + } + continue; + } + int? integer = Parse.Integer(atom); + if (integer != null) + { + mMetadata.NumPlayers.Add(integer.Value); + continue; + } + + throw new ParserException("Unexpected atom on line " + mInput.LineNumber + ": " + atom); + } + if (mMetadata.NumPlayers.Count == 0) { - ThrowException("Invalid range", pair[1]); + throw new ParserException("No numbers given on line " + mInput.LineNumber + ": " + pair[1]); } } else { - ThrowException("Invalid value", pair[1]); + throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]); } } else if (pair[0] == "author") @@ -178,11 +183,11 @@ namespace CarFire string author = Parse.String(pair[1]); if (author != null) { - mData.Author = author; + mMetadata.Author = author; } else { - ThrowException("Invalid value", pair[1]); + throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]); } } else if (pair[0] == "levelname") @@ -190,16 +195,16 @@ namespace CarFire string level = Parse.String(pair[1]); if (level != null) { - mData.Name = level; + mMetadata.Name = level; } else { - ThrowException("Invalid value", pair[1]); + throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]); } } else { - Console.WriteLine("Unimplemented key: " + pair[0]); + throw new ParserException("Unexpected key on line " + mInput.LineNumber + ": " + pair[0]); } } else @@ -213,33 +218,35 @@ namespace CarFire string ReadMapTableSection() { - if (mData.Dimensions.X == 0 || mData.Dimensions.Y == 0) + if (mMetadata == null || mMetadata.GridWidth == 0 || mMetadata.GridHeight == 0) { - ThrowException("Unexpected section", "You must define the map dimensions before this section."); + throw new ParserException("Unexpected section on line " + mInput.LineNumber + + ": You must define the map dimensions before this section."); } - mData.Grid = new char[mData.Dimensions.X, mData.Dimensions.Y]; + mGrid = new char[mMetadata.GridWidth, mMetadata.GridHeight]; int y; - for (y = 0; y < mData.Dimensions.Y && mLineNumber < mExpectedNumberOfLines; y++) + for (y = 0; y < mMetadata.GridHeight && !mInput.End; y++) { - string line = ReadLine(); - mLineNumber++; + string line = mInput.ReadLine(); - if (line.Length < mData.Dimensions.X) + if (line.Length < mMetadata.GridWidth) { - ThrowException("Not enough characters", "Expecting " + mData.Dimensions.X + " characters."); + throw new ParserException("Unexpected EOL on line " + mInput.LineNumber + + ": The number of characters should match the width dimension (" + mMetadata.GridWidth + ")."); } - for (int x = 0; x < mData.Dimensions.X; x++) + for (int x = 0; x < mMetadata.GridWidth; x++) { - mData.Grid[x, y] = line[x]; + mGrid[x, y] = line[x]; } } - if (y < mData.Dimensions.Y) + if (y < mMetadata.GridHeight) { - ThrowException("Unexpected ", ""); + throw new ParserException("Unexpected EOF on line " + mInput.LineNumber + + ": The number of lines in this section should match the height dimension (" + mMetadata.GridHeight + ")."); } return null; @@ -247,15 +254,17 @@ namespace CarFire string ReadEntitySection(char entity) { - while (mLineNumber < mExpectedNumberOfLines) + Dictionary pairs = new Dictionary(); + mEntities[entity] = pairs; + + while (!mInput.End) { - string line = ReadLine(); - mLineNumber++; + string line = mInput.ReadLine(); string[] pair = Parse.KeyValuePair(line); if (pair != null) { - // TODO + pairs[pair[0]] = pair[1]; } else { @@ -266,22 +275,56 @@ namespace CarFire return null; } - #endregion - - - #region Private Methods bool IsLineSignificant(string line) { - if (line.Length == 0 || Regex.IsMatch(line, @"^;|^\s*$")) return false; + if (line.Trim().Length == 0 || Parse.IniComment(line) != null) return false; return true; } - void ThrowException(string problem, string text) + #endregion + + + #region Private Types + + /// + /// This private class wraps around ContentReader to make it more + /// convenient to use it as an input stream reader. + /// + class LineReader { - throw new ParserException(problem + " on line " + mLineNumber + ": " + text); + ContentReader mInput; + int mLineNumber = 0; + int mExpectedNumberOfLines; + + public LineReader(ContentReader input) + { + mInput = input; + mExpectedNumberOfLines = mInput.ReadInt32(); + } + + public string ReadLine() + { + mLineNumber++; + return mInput.ReadString(); + } + + public int LineNumber { get { return mLineNumber; } } + + public bool End { get { return mLineNumber >= mExpectedNumberOfLines; } } } #endregion + + + #region Private Variables + + Map.Metadata mMetadata; + char[,] mGrid; + Dictionary> mEntities = new Dictionary>(); + + LineReader mInput; + + #endregion } }