2 using System.Collections.Generic;
4 using System.Runtime.Serialization;
5 using System.Text.RegularExpressions;
6 using Microsoft.Xna.Framework;
7 using Microsoft.Xna.Framework.Content;
8 using Microsoft.Xna.Framework.Graphics;
13 /// This class will be instantiated by the XNA Framework Content
14 /// Pipeline to read cfmap files from binary .xnb format.
16 public class MapReader : ContentTypeReader<Map>
18 public class ParserException : System.ApplicationException
20 public ParserException()
24 public ParserException(string message) :
29 public ParserException(string message, System.Exception inner) :
34 protected ParserException(SerializationInfo info, StreamingContext context) :
42 int mExpectedNumberOfLines;
47 protected override Map Read(ContentReader input, Map existingInstance)
50 mExpectedNumberOfLines = mInput.ReadInt32();
54 return new Map(mData);
58 #region Private Reading Methods
62 return mInput.ReadString();
67 mData = new Map.Data();
69 while (mLineNumber < mExpectedNumberOfLines)
71 string line = ReadLine();
76 if (!IsLineSignificant(line)) break;
78 string section = Parse.IniSectionHeader(line);
81 if (section == "metadata")
83 line = ReadMetadataSection();
85 else if (section == "maptable")
87 line = ReadMapTableSection();
89 else if (section.Length == 1)
91 line = ReadEntitySection(section[0]);
95 ThrowException("Unknown section", section);
100 ThrowException("Unexpected text", line);
106 string ReadMetadataSection()
108 while (mLineNumber < mExpectedNumberOfLines)
110 string line = ReadLine();
113 if (!IsLineSignificant(line)) continue;
115 string[] pair = Parse.KeyValuePair(line);
118 if (pair[0] == "type")
120 object type = Parse.Constant<Map.Type>(pair[1]);
123 mData.Type = (Map.Type)type;
127 ThrowException("Invalid type", pair[1]);
130 else if (pair[0] == "dimensions")
132 Point? dimensions = Parse.Coordinates(pair[1]);
133 if (dimensions != null)
135 mData.Dimensions = dimensions.Value;
136 if (mData.Dimensions.X <= 0 || mData.Dimensions.Y <= 0)
138 ThrowException("Invalid dimensions", pair[1]);
143 ThrowException("Invalid value", pair[1]);
146 else if (pair[0] == "tileset")
148 string tileset = Parse.String(pair[1]);
151 mData.Tileset = tileset;
155 ThrowException("Invalid tileset", pair[1]);
158 else if (pair[0] == "numplayers")
160 int[] numPlayers = Parse.Range(pair[1]);
161 if (numPlayers != null)
163 mData.MinNumPlayers = numPlayers[0];
164 mData.MaxNumPlayers = numPlayers[1];
165 if (mData.MinNumPlayers <= 0 || mData.MaxNumPlayers <= 0 ||
166 mData.MinNumPlayers > mData.MaxNumPlayers)
168 ThrowException("Invalid range", pair[1]);
173 ThrowException("Invalid value", pair[1]);
176 else if (pair[0] == "author")
178 string author = Parse.String(pair[1]);
181 mData.Author = author;
185 ThrowException("Invalid value", pair[1]);
188 else if (pair[0] == "levelname")
190 string level = Parse.String(pair[1]);
197 ThrowException("Invalid value", pair[1]);
202 Console.WriteLine("Unimplemented key: " + pair[0]);
214 string ReadMapTableSection()
216 if (mData.Dimensions.X == 0 || mData.Dimensions.Y == 0)
218 ThrowException("Unexpected section", "You must define the map dimensions before this section.");
221 mData.Grid = new char[mData.Dimensions.X, mData.Dimensions.Y];
224 for (y = 0; y < mData.Dimensions.Y && mLineNumber < mExpectedNumberOfLines; y++)
226 string line = ReadLine();
229 if (line.Length < mData.Dimensions.X)
231 ThrowException("Not enough characters", "Expecting " + mData.Dimensions.X + " characters.");
234 for (int x = 0; x < mData.Dimensions.X; x++)
236 mData.Grid[x, y] = line[x];
240 if (y < mData.Dimensions.Y)
242 ThrowException("Unexpected ", "");
248 string ReadEntitySection(char entity)
250 while (mLineNumber < mExpectedNumberOfLines)
252 string line = ReadLine();
255 string[] pair = Parse.KeyValuePair(line);
272 #region Private Methods
274 bool IsLineSignificant(string line)
276 if (line.Length == 0 || Regex.IsMatch(line, @"^;|^\s*$")) return false;
280 void ThrowException(string problem, string text)
282 throw new ParserException(problem + " on line " + mLineNumber + ": " + text);