X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=CarFire%2FCarFire%2FCarFire%2FMapReader.cs;h=3d43f3619a8929152a062d4677032f2528635547;hb=d0bdd76b2cfd38fe985a7493f42b5d6e0f79ac91;hp=fbae4df99f8b7988a1e2f9f7069c7062c470af24;hpb=1393586d1e5639ac8f1e9fc8183644050dd54165;p=chaz%2Fcarfire
diff --git a/CarFire/CarFire/CarFire/MapReader.cs b/CarFire/CarFire/CarFire/MapReader.cs
index fbae4df..3d43f36 100644
--- a/CarFire/CarFire/CarFire/MapReader.cs
+++ b/CarFire/CarFire/CarFire/MapReader.cs
@@ -5,6 +5,7 @@ using System.Runtime.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
+using System.Reflection;
namespace CarFire
{
@@ -42,276 +43,393 @@ namespace CarFire
protected override Map Read(ContentReader input, Map existingInstance)
{
- mInput = new LineReader(input);
- ReadSectionHeaders();
- return new Map(mMetadata, mGrid, mEntities);
+ mImpl = new Impl(input);
+ return mImpl.GetMap();
}
#endregion
- #region Private Methods
+ #region Private Types
- void ReadSectionHeaders()
+ ///
+ /// This private class wraps around ContentReader to make it more
+ /// convenient to use it as an input stream reader.
+ ///
+ class LineReader
{
- mMetadata = new Map.Metadata();
+ ContentReader mInput;
+ int mLineNumber = 0;
+ int mExpectedNumberOfLines;
+
+ public LineReader(ContentReader input)
+ {
+ mInput = input;
+ mExpectedNumberOfLines = mInput.ReadInt32();
+ }
- while (!mInput.End)
+ public string ReadLine()
{
- string line = mInput.ReadLine();
+ mLineNumber++;
+ return mInput.ReadString();
+ }
- while (line != null)
+ public int LineNumber { get { return mLineNumber; } }
+
+ public bool End { get { return mLineNumber >= mExpectedNumberOfLines; } }
+ }
+
+
+ ///
+ /// This class is the actual implementation. The implementation is wrapped
+ /// in a subclass because the invoker seems to only be able to invoke public
+ /// methods, and this needs to invoke methods that shouldn't be public.
+ ///
+ class Impl
+ {
+ public Impl(ContentReader input)
+ {
+ mInput = new LineReader(input);
+ ReadSectionHeaders();
+ PostProcess();
+ }
+
+ public Map GetMap()
+ {
+ return new Map(mMetadata, mGrid, mEntities);
+ }
+
+
+ public void ReadSectionHeaders()
+ {
+ mMetadata = new Map.Metadata();
+
+ while (!mInput.End)
{
- if (!IsLineSignificant(line)) break;
+ string line = mInput.ReadLine();
- string section = Parse.IniSectionHeader(line);
- if (section != null)
+ while (line != null)
{
- if (section == "metadata")
+ if (!IsLineSignificant(line)) break;
+
+ string section = Parse.IniSectionHeader(line);
+ if (section != null)
{
- line = ReadMetadataSection();
+ if (section == "metadata")
+ {
+ line = ReadMetadataSection();
+ }
+ else if (section == "maptable")
+ {
+ line = ReadMapTableSection();
+ }
+ else if (section.Length == 1 && IsValidEntityIdentifier(section[0]))
+ {
+ line = ReadEntitySection(section[0]);
+ }
+ else
+ {
+ throw new ParserException("Unexpected section on line " + mInput.LineNumber + ": " + section);
+ }
}
- else if (section == "maptable")
+ else
{
- line = ReadMapTableSection();
+ throw new ParserException("Unexpected text on line " + mInput.LineNumber + ": " + line);
}
- else if (section.Length == 1)
+ }
+ }
+ }
+
+ string ReadMetadataSection()
+ {
+ while (!mInput.End)
+ {
+ string line = mInput.ReadLine();
+ if (!IsLineSignificant(line)) continue;
+
+ string[] pair = Parse.KeyValuePair(line);
+ if (pair != null)
+ {
+ try
{
- line = ReadEntitySection(section[0]);
+ string methodName = "set_" + pair[0].ToLowerInvariant();
+ object[] args = new object[1];
+ args[0] = pair[1];
+ GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, this, args);
}
- else
+#pragma warning disable 0168
+ catch (System.MissingMethodException ex)
+#pragma warning restore 0168
{
- throw new ParserException("Unexpected section on line " + mInput.LineNumber + ": " + section);
+ throw new ParserException("Unexpected key on line " + mInput.LineNumber + ": " + pair[0]);
}
}
else
{
- throw new ParserException("Unexpected text on line " + mInput.LineNumber + ": " + line);
+ return line;
}
}
+
+ return null;
}
- }
- string ReadMetadataSection()
- {
- while (!mInput.End)
+ string ReadMapTableSection()
{
- string line = mInput.ReadLine();
- if (!IsLineSignificant(line)) continue;
+ if (mMetadata == null || mMetadata.GridWidth == 0 || mMetadata.GridHeight == 0)
+ {
+ throw new ParserException("Unexpected section on line " + mInput.LineNumber +
+ ": You must define the map dimensions before this section.");
+ }
- string[] pair = Parse.KeyValuePair(line);
- if (pair != null)
+ mGrid = new char[mMetadata.GridWidth, mMetadata.GridHeight];
+
+ int y;
+ for (y = 0; y < mMetadata.GridHeight && !mInput.End; y++)
{
- if (pair[0] == "type")
+ string line = mInput.ReadLine();
+
+ if (line.Length < mMetadata.GridWidth)
{
- Map.Type type = Parse.Constant(pair[1]);
- if (type != default(Map.Type))
- {
- mMetadata.Type = type;
- }
- else
- {
- throw new ParserException("Unexpected type on line " + mInput.LineNumber + ": " + pair[1]);
- }
+ throw new ParserException("Unexpected EOL on line " + mInput.LineNumber +
+ ": The number of characters should match the width dimension (" + mMetadata.GridWidth + ").");
}
- else if (pair[0] == "dimensions")
+
+ for (int x = 0; x < mMetadata.GridWidth; x++)
{
- Point? dimensions = Parse.Coordinates(pair[1]);
- if (dimensions != null)
- {
- mMetadata.GridWidth = dimensions.Value.X;
- mMetadata.GridHeight = dimensions.Value.Y;
- if (mMetadata.GridWidth <= 0 || mMetadata.GridHeight <= 0)
- {
- throw new ParserException("Invalid dimensions on line " + mInput.LineNumber + ": " + pair[1]);
- }
- }
- else
- {
- throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
- }
+ mGrid[x, y] = line[x];
}
- else if (pair[0] == "tileset")
+ }
+
+ if (y < mMetadata.GridHeight)
+ {
+ 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;
+ }
+
+ string ReadEntitySection(char identifier)
+ {
+ Dictionary pairs = new Dictionary();
+ mEntitySections[identifier] = pairs;
+
+ while (!mInput.End)
+ {
+ string line = mInput.ReadLine();
+
+ string[] pair = Parse.KeyValuePair(line);
+ if (pair != null)
{
- string tileset = Parse.String(pair[1]);
- if (tileset != null)
- {
- mMetadata.Tileset = tileset;
- }
- else
- {
- throw new ParserException("Unexpected tileset on line " + mInput.LineNumber + ": " + pair[1]);
- }
+ pairs[pair[0]] = pair[1];
}
- else if (pair[0] == "numplayers")
+ else
{
- string[] list = Parse.List(pair[1]);
- if (list != null)
+ return line;
+ }
+ }
+
+ return null;
+ }
+
+
+ void PostProcess()
+ {
+ if (mMetadata == null || mGrid == null)
+ {
+ throw new ParserException("Missing a required section. Make sure the metadata and grid are there.");
+ }
+
+ mEntities = new List();
+ mPlayerPositions = new Point[mMetadata.NumPlayers.Max() + 1];
+
+ // create entities defined completely
+ foreach (char identifier in mEntitySections.Keys)
+ {
+ Dictionary pairs = mEntitySections[identifier];
+ if (pairs.ContainsKey("create"))
+ {
+ string[] list = Parse.List(pairs["create"]);
+ foreach (string positionString in list)
{
- foreach (string atom in list)
+ Point? position = Parse.Coordinates(positionString);
+ if (position != null)
{
- 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);
+ Map.RawEntity createEntity = new Map.RawEntity();
+ createEntity.Id = identifier;
+ createEntity.Position = position.Value;
+ createEntity.Attributes = pairs;
+ mEntities.Add(createEntity);
}
- if (mMetadata.NumPlayers.Count == 0)
+ else
{
- throw new ParserException("No numbers given on line " + mInput.LineNumber + ": " + pair[1]);
+ throw new ParserException("Unexpected value of key `create' defined for entity " + identifier + ".");
}
}
- else
- {
- throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
- }
+ pairs.Remove("create");
}
- else if (pair[0] == "author")
- {
- string author = Parse.String(pair[1]);
- if (author != null)
- {
- mMetadata.Author = author;
- }
- else
- {
- throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
- }
- }
- else if (pair[0] == "levelname")
+ }
+
+ // create entities with positions defined on the grid
+ // and get player starting positions
+ for (int x = 0; x < mMetadata.GridWidth; x++)
+ {
+ for (int y = 0; y < mMetadata.GridHeight; y++)
{
- string level = Parse.String(pair[1]);
- if (level != null)
+ char identifier = mGrid[x, y];
+ if (IsValidEntityIdentifier(identifier))
{
- mMetadata.Name = level;
+ if (mEntitySections.ContainsKey(identifier))
+ {
+ Map.RawEntity createEntity = new Map.RawEntity();
+ createEntity.Id = identifier;
+ createEntity.Position = new Point(x, y);
+ createEntity.Attributes = mEntitySections[identifier];
+ mEntities.Add(createEntity);
+ }
+ else
+ {
+ throw new ParserException("Unexpected entity (" + identifier +
+ ") placed on the grid at [" + x + "," + y + "] but not defined.");
+ }
+ mGrid[x, y] = mDefaultTile;
}
- else
+ else if ('1' <= identifier && identifier <= '9')
{
- throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + pair[1]);
+ int playerNum = identifier - 48;
+ if (playerNum < mPlayerPositions.Count())
+ {
+ mPlayerPositions[playerNum] = new Point(x, y);
+ }
+ mGrid[x, y] = mDefaultTile;
}
}
- else
- {
- throw new ParserException("Unexpected key on line " + mInput.LineNumber + ": " + pair[0]);
- }
}
- else
+
+ // check if all needed player positions are defined
+ for (int i = 1; i < mPlayerPositions.Count(); i++)
{
- return line;
+ if (mPlayerPositions[i] == default(Point))
+ {
+ throw new ParserException("Not enough player positions were defined on the grid; " +
+ "you are missing a spot for player " + i + ".");
+ }
}
}
- return null;
- }
- string ReadMapTableSection()
- {
- if (mMetadata == null || mMetadata.GridWidth == 0 || mMetadata.GridHeight == 0)
+ bool IsLineSignificant(string line)
{
- throw new ParserException("Unexpected section on line " + mInput.LineNumber +
- ": You must define the map dimensions before this section.");
+ if (line.Trim().Length == 0 || Parse.IniComment(line) != null) return false;
+ return true;
}
- mGrid = new char[mMetadata.GridWidth, mMetadata.GridHeight];
-
- int y;
- for (y = 0; y < mMetadata.GridHeight && !mInput.End; y++)
+ bool IsValidEntityIdentifier(char id)
{
- string line = mInput.ReadLine();
+ if (('a' <= id && id <= 'z') || ('A' <= id && id <= 'Z')) return true;
+ return false;
+ }
- if (line.Length < mMetadata.GridWidth)
- {
- 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 < mMetadata.GridWidth; x++)
- {
- mGrid[x, y] = line[x];
- }
+ public void set_author(string atom)
+ {
+ string value = Parse.String(atom);
+ if (value != null) mMetadata.Author = value;
+ else throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + atom);
}
- if (y < mMetadata.GridHeight)
+ public void set_levelname(string atom)
{
- throw new ParserException("Unexpected EOF on line " + mInput.LineNumber +
- ": The number of lines in this section should match the height dimension (" + mMetadata.GridHeight + ").");
+ string value = Parse.String(atom);
+ if (value != null) mMetadata.Name = value;
+ else throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + atom);
}
- return null;
- }
-
- string ReadEntitySection(char entity)
- {
- Dictionary pairs = new Dictionary();
- mEntities[entity] = pairs;
-
- while (!mInput.End)
+ public void set_type(string atom)
{
- string line = mInput.ReadLine();
+ Map.Mode value = Parse.Constant(atom);
+ if (value != default(Map.Mode)) mMetadata.Type = value;
+ else throw new ParserException("Unexpected type on line " + mInput.LineNumber + ": " + atom);
+ }
- string[] pair = Parse.KeyValuePair(line);
- if (pair != null)
+ public void set_dimensions(string atom)
+ {
+ Point? dimensions = Parse.Coordinates(atom);
+ if (dimensions != null)
{
- pairs[pair[0]] = pair[1];
+ mMetadata.GridWidth = dimensions.Value.X;
+ mMetadata.GridHeight = dimensions.Value.Y;
+ if (mMetadata.GridWidth <= 0 || mMetadata.GridHeight <= 0)
+ {
+ throw new ParserException("Invalid dimensions on line " + mInput.LineNumber + ": " + atom);
+ }
}
else
{
- return line;
+ throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + atom);
}
}
- return null;
- }
-
-
- bool IsLineSignificant(string line)
- {
- if (line.Trim().Length == 0 || Parse.IniComment(line) != null) return false;
- return true;
- }
-
- #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
- {
- ContentReader mInput;
- int mLineNumber = 0;
- int mExpectedNumberOfLines;
+ public void set_tileset(string atom)
+ {
+ string value = Parse.String(atom);
+ if (value != null) mMetadata.Tileset = value;
+ else throw new ParserException("Unexpected tileset on line " + mInput.LineNumber + ": " + atom);
+ }
- public LineReader(ContentReader input)
+ public void set_defaulttile(string atom)
{
- mInput = input;
- mExpectedNumberOfLines = mInput.ReadInt32();
+ char? value = Parse.Char(atom);
+ if (value != null) mDefaultTile = value.Value;
+ else throw new ParserException("Unexpected tile value on line " + mInput.LineNumber + ": " + atom);
}
- public string ReadLine()
+ public void set_numplayers(string atom)
{
- mLineNumber++;
- return mInput.ReadString();
+ string[] list = Parse.List(atom);
+ if (list != null)
+ {
+ foreach (string item in list)
+ {
+ int[] range = Parse.Range(item);
+ if (range != null)
+ {
+ for (int i = range[0]; i <= range[1]; i++)
+ {
+ mMetadata.NumPlayers.Add(i);
+ }
+ continue;
+ }
+ int? integer = Parse.Integer(item);
+ if (integer != null)
+ {
+ mMetadata.NumPlayers.Add(integer.Value);
+ continue;
+ }
+
+ throw new ParserException("Unexpected atom on line " + mInput.LineNumber + ": " + item);
+ }
+ if (mMetadata.NumPlayers.Count == 0)
+ {
+ throw new ParserException("No numbers given on line " + mInput.LineNumber + ": " + atom);
+ }
+ }
+ else
+ {
+ throw new ParserException("Unexpected value on line " + mInput.LineNumber + ": " + atom);
+ }
}
- public int LineNumber { get { return mLineNumber; } }
- public bool End { get { return mLineNumber >= mExpectedNumberOfLines; } }
+ Map.Metadata mMetadata;
+ char[,] mGrid;
+ List mEntities;
+ Point[] mPlayerPositions;
+
+ Dictionary> mEntitySections = new Dictionary>();
+ char mDefaultTile = ' ';
+
+ LineReader mInput;
}
#endregion
@@ -319,11 +437,7 @@ namespace CarFire
#region Private Variables
- Map.Metadata mMetadata;
- char[,] mGrid;
- Dictionary> mEntities = new Dictionary>();
-
- LineReader mInput;
+ Impl mImpl;
#endregion
}