]> Dogcows Code - chaz/carfire/blob - CarFire/CarFire/CarFire/MapReader.cs
Map drawing implemented.
[chaz/carfire] / CarFire / CarFire / CarFire / MapReader.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Runtime.Serialization;
5 using Microsoft.Xna.Framework;
6 using Microsoft.Xna.Framework.Content;
7 using Microsoft.Xna.Framework.Graphics;
8
9 namespace CarFire
10 {
11 /// <summary>
12 /// This class will be instantiated by the XNA Framework Content
13 /// Pipeline to read cfmap files from binary .xnb format.
14 /// </summary>
15 public class MapReader : ContentTypeReader<Map>
16 {
17 #region Public Exceptions
18
19 /// <summary>
20 /// This exception is thrown during the loading of a map if any
21 /// part of the map file is inconsistent with the expected format
22 /// and order.
23 /// </summary>
24 public class ParserException : System.ApplicationException
25 {
26 public ParserException() {}
27
28 public ParserException(string message) :
29 base(message) {}
30
31 public ParserException(string message, System.Exception inner) :
32 base(message, inner) {}
33
34 protected ParserException(SerializationInfo info, StreamingContext context) :
35 base(info, context) {}
36 }
37
38 #endregion
39
40
41 #region Protected Methods
42
43 protected override Map Read(ContentReader input, Map existingInstance)
44 {
45 mInput = new LineReader(input);
46 ReadSectionHeaders();
47 return new Map(mMetadata, mGrid, mEntities);
48 }
49
50 #endregion
51
52
53 #region Private Methods
54
55 void ReadSectionHeaders()
56 {
57 mMetadata = new Map.Metadata();
58
59 while (!mInput.End)
60 {
61 string line = mInput.ReadLine();
62
63 while (line != null)
64 {
65 if (!IsLineSignificant(line)) break;
66
67 string section = Parse.IniSectionHeader(line);
68 if (section != null)
69 {
70 if (section == "metadata")
71 {
72 line = ReadMetadataSection();
73 }
74 else if (section == "maptable")
75 {
76 line = ReadMapTableSection();
77 }
78 else if (section.Length == 1)
79 {
80 line = ReadEntitySection(section[0]);
81 }
82 else
83 {
84 throw new ParserException("Unexpected section on line " + mInput.LineNumber + ": " + section);
85 }
86 }
87 else
88 {
89 throw new ParserException("Unexpected text on line " + mInput.LineNumber + ": " + line);
90 }
91 }
92 }
93 }
94
95 string ReadMetadataSection()
96 {
97 while (!mInput.End)
98 {
99 string line = mInput.ReadLine();
100 if (!IsLineSignificant(line)) continue;
101
102 string[] pair = Parse.KeyValuePair(line);
103 if (pair != null)
104 {
105 if (pair[0] == "type")
106 {
107 Map.Type type = Parse.Constant<Map.Type>(pair[1]);
108 if (type != default(Map.Type))
109 {
110 mMetadata.Type = type;
111 }
112 else
113 {
114 throw new ParserException("Unexpected type on line " + mInput.LineNumber + ": " + pair[1]);
115 }
116 }
117 else if (pair[0] == "dimensions")
118 {
119 Point? dimensions = Parse.Coordinates(pair[1]);
120 if (dimensions != null)
121 {
122 mMetadata.GridWidth = dimensions.Value.X;
123 mMetadata.GridHeight = dimensions.Value.Y;
124 if (mMetadata.GridWidth <= 0 || mMetadata.GridHeight <= 0)
125 {
126 throw new ParserException("Invalid dimensions on line " + mInput.LineNumber + ": " + pair[1]);
127 }
128 }
129 else
130 {
131 throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
132 }
133 }
134 else if (pair[0] == "tileset")
135 {
136 string tileset = Parse.String(pair[1]);
137 if (tileset != null)
138 {
139 mMetadata.Tileset = tileset;
140 }
141 else
142 {
143 throw new ParserException("Unexpected tileset on line " + mInput.LineNumber + ": " + pair[1]);
144 }
145 }
146 else if (pair[0] == "numplayers")
147 {
148 string[] list = Parse.List(pair[1]);
149 if (list != null)
150 {
151 foreach (string atom in list)
152 {
153 int[] range = Parse.Range(atom);
154 if (range != null)
155 {
156 for (int i = range[0]; i <= range[1]; i++)
157 {
158 mMetadata.NumPlayers.Add(i);
159 }
160 continue;
161 }
162 int? integer = Parse.Integer(atom);
163 if (integer != null)
164 {
165 mMetadata.NumPlayers.Add(integer.Value);
166 continue;
167 }
168
169 throw new ParserException("Unexpected atom on line " + mInput.LineNumber + ": " + atom);
170 }
171 if (mMetadata.NumPlayers.Count == 0)
172 {
173 throw new ParserException("No numbers given on line " + mInput.LineNumber + ": " + pair[1]);
174 }
175 }
176 else
177 {
178 throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
179 }
180 }
181 else if (pair[0] == "author")
182 {
183 string author = Parse.String(pair[1]);
184 if (author != null)
185 {
186 mMetadata.Author = author;
187 }
188 else
189 {
190 throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
191 }
192 }
193 else if (pair[0] == "levelname")
194 {
195 string level = Parse.String(pair[1]);
196 if (level != null)
197 {
198 mMetadata.Name = level;
199 }
200 else
201 {
202 throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
203 }
204 }
205 else
206 {
207 throw new ParserException("Unexpected key on line " + mInput.LineNumber + ": " + pair[0]);
208 }
209 }
210 else
211 {
212 return line;
213 }
214 }
215
216 return null;
217 }
218
219 string ReadMapTableSection()
220 {
221 if (mMetadata == null || mMetadata.GridWidth == 0 || mMetadata.GridHeight == 0)
222 {
223 throw new ParserException("Unexpected section on line " + mInput.LineNumber +
224 ": You must define the map dimensions before this section.");
225 }
226
227 mGrid = new char[mMetadata.GridWidth, mMetadata.GridHeight];
228
229 int y;
230 for (y = 0; y < mMetadata.GridHeight && !mInput.End; y++)
231 {
232 string line = mInput.ReadLine();
233
234 if (line.Length < mMetadata.GridWidth)
235 {
236 throw new ParserException("Unexpected EOL on line " + mInput.LineNumber +
237 ": The number of characters should match the width dimension (" + mMetadata.GridWidth + ").");
238 }
239
240 for (int x = 0; x < mMetadata.GridWidth; x++)
241 {
242 mGrid[x, y] = line[x];
243 }
244 }
245
246 if (y < mMetadata.GridHeight)
247 {
248 throw new ParserException("Unexpected EOF on line " + mInput.LineNumber +
249 ": The number of lines in this section should match the height dimension (" + mMetadata.GridHeight + ").");
250 }
251
252 return null;
253 }
254
255 string ReadEntitySection(char entity)
256 {
257 Dictionary<string, string> pairs = new Dictionary<string, string>();
258 mEntities[entity] = pairs;
259
260 while (!mInput.End)
261 {
262 string line = mInput.ReadLine();
263
264 string[] pair = Parse.KeyValuePair(line);
265 if (pair != null)
266 {
267 pairs[pair[0]] = pair[1];
268 }
269 else
270 {
271 return line;
272 }
273 }
274
275 return null;
276 }
277
278
279 bool IsLineSignificant(string line)
280 {
281 if (line.Trim().Length == 0 || Parse.IniComment(line) != null) return false;
282 return true;
283 }
284
285 #endregion
286
287
288 #region Private Types
289
290 /// <summary>
291 /// This private class wraps around ContentReader to make it more
292 /// convenient to use it as an input stream reader.
293 /// </summary>
294 class LineReader
295 {
296 ContentReader mInput;
297 int mLineNumber = 0;
298 int mExpectedNumberOfLines;
299
300 public LineReader(ContentReader input)
301 {
302 mInput = input;
303 mExpectedNumberOfLines = mInput.ReadInt32();
304 }
305
306 public string ReadLine()
307 {
308 mLineNumber++;
309 return mInput.ReadString();
310 }
311
312 public int LineNumber { get { return mLineNumber; } }
313
314 public bool End { get { return mLineNumber >= mExpectedNumberOfLines; } }
315 }
316
317 #endregion
318
319
320 #region Private Variables
321
322 Map.Metadata mMetadata;
323 char[,] mGrid;
324 Dictionary<char, Dictionary<string, string>> mEntities = new Dictionary<char, Dictionary<string, string>>();
325
326 LineReader mInput;
327
328 #endregion
329 }
330 }
This page took 0.049491 seconds and 4 git commands to generate.