From 2516116c4866415c336c724535580047375f69d3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 7 Jun 2009 15:11:51 +0100 Subject: [PATCH] XML loading and saving of stations --- include/IMap.hpp | 6 +-- include/IStation.hpp | 5 +++ include/IXMLParser.hpp | 1 + maps/coal_mine.xml | 44 +++++++++++++++++++ schemas/map.xsd | 18 ++++++++ src/Map.cpp | 97 +++++++++++++++++++++++++++++++++++++++--- src/Station.cpp | 6 ++- src/XMLParser.cpp | 2 + 8 files changed, 169 insertions(+), 10 deletions(-) diff --git a/include/IMap.hpp b/include/IMap.hpp index 888e066..2eef127 100644 --- a/include/IMap.hpp +++ b/include/IMap.hpp @@ -39,9 +39,6 @@ public: // first virtual ITrackSegmentPtr trackAt(const Point& aPoint) const = 0; - // Return the station at this track location or a null pointer - virtual IStationPtr stationAt(Point aPoint) const = 0; - // True if the given position is the origin of a track segment virtual bool isValidTrack(const Point& aPoint) const = 0; @@ -51,6 +48,9 @@ public: virtual void setTrackAt(const Point& aPoint, ITrackSegmentPtr aTrack) = 0; + // Return the station at this track location or a null pointer + virtual IStationPtr stationAt(Point aPoint) const = 0; + // Delete the contents of a tile virtual void eraseTile(int x, int y) = 0; diff --git a/include/IStation.hpp b/include/IStation.hpp index 583d37d..3536798 100644 --- a/include/IStation.hpp +++ b/include/IStation.hpp @@ -41,6 +41,11 @@ struct IStation { virtual const string& name() const = 0; virtual void setName(const string& aName) = 0; + // A station has an ID that uniquely identifies it + // Setting is allowed to support the map loader + virtual int id() const = 0; + virtual void setId(int anId) = 0; + // A station has a random colour that is used to identify it when // the highlight is drawn typedef tuple HighlightColour; diff --git a/include/IXMLParser.hpp b/include/IXMLParser.hpp index 35e75f3..4fedd43 100644 --- a/include/IXMLParser.hpp +++ b/include/IXMLParser.hpp @@ -66,6 +66,7 @@ struct IXMLCallback { virtual void startElement(const std::string& localName, const AttributeSet& attrs) = 0; + virtual void endElement(const std::string& localName) = 0; virtual void text(const std::string& localName, const std::string& aString) = 0; }; diff --git a/maps/coal_mine.xml b/maps/coal_mine.xml index 67da636..53c6beb 100644 --- a/maps/coal_mine.xml +++ b/maps/coal_mine.xml @@ -4,6 +4,14 @@ + +Yahyahyah + + + +Grimethorpe + + maps/coal_mine.bin @@ -73,34 +81,50 @@ + + + + + + + + + + + + + + + + @@ -145,42 +169,62 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/schemas/map.xsd b/schemas/map.xsd index 5e60ee8..17490af 100644 --- a/schemas/map.xsd +++ b/schemas/map.xsd @@ -14,6 +14,17 @@ + + + + + + + + + + @@ -45,6 +56,13 @@ + + + + + + diff --git a/src/Map.cpp b/src/Map.cpp index de3f09b..aff48c5 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -30,10 +30,13 @@ #include #include #include +#include +#include #include #include #include +#include // A single piece of track may appear multiple times in the map - this // will be true for all track segments that cover multiple tiles @@ -106,6 +109,9 @@ public: Point botLeft, Point topRight); void postRenderSector(IGraphicsPtr aContext, int id, Point botLeft, Point topRight); + + // Inteface used soley by MapLoader + void setStationAt(int x, int y, IStationPtr aStation); private: // Tiles on the map struct Tile { @@ -225,6 +231,11 @@ IStationPtr Map::stationAt(Point aPoint) const return tileAt(aPoint.x, aPoint.y).station; } +void Map::setStationAt(int x, int y, IStationPtr aStation) +{ + tileAt(x, y).station = aStation; +} + void Map::eraseTile(int x, int y) { Tile& tile = tileAt(x, y); @@ -1085,6 +1096,25 @@ void Map::save(const string& aFileName) .addAttribute("dirX", myStartDirection.x) .addAttribute("dirY", myStartDirection.z)); + // Write out all the stations + set seenStations; + + for (int x = 0; x < myWidth; x++) { + for (int y = 0; y < myDepth; y++) { + IStationPtr s = tileAt(x, y).station; + + if (s && seenStations.find(s) == seenStations.end()) { + // Not seen this station before + root.addChild + (xml::element("station") + .addAttribute("id", s->id()) + .addChild(xml::element("name").addText(s->name()))); + + seenStations.insert(s); + } + } + } + // Generate the height map // Note: basename is deprecated (use .replace_extension() instead when // boost is updated in Debian) @@ -1101,16 +1131,29 @@ void Map::save(const string& aFileName) for (int y = 0; y < myDepth; y++) { const Tile& tile = tileAt(x, y); + bool useful = false; + xml::element tileXml("tile"); + + tileXml.addAttribute("x", x); + tileXml.addAttribute("y", y); + if (tile.track && tile.track->originX() == x && tile.track->originY() == y) { - - tileset.addChild - (xml::element("tile") - .addAttribute("x", x) - .addAttribute("y", y) - .addChild(tile.track->get()->toXml())); + + tileXml.addChild(tile.track->get()->toXml()); + useful = true; } + + if (tile.station) { + tileXml.addChild + (xml::element("stationPart") + .addAttribute("id", tile.station->id())); + useful = true; + } + + if (useful) + tileset.addChild(tileXml); } } @@ -1147,12 +1190,28 @@ public: handleCurvedTrack(attrs); else if (localName == "crossoverTrack") handleCrossoverTrack(attrs); + else if (localName == "stationPart") + handleStationPart(attrs); + else if (localName == "station") + handleStation(attrs); } + void endElement(const string& localName) + { + if (localName == "station") + myActiveStation.reset(); + } + void text(const string& localName, const string& aString) { if (localName == "heightmap") myMap->readHeightMap(aString); + else if (myActiveStation) { + if (localName == "name") { + debug() << "Saw station " << aString; + myActiveStation->setName(aString); + } + } } private: @@ -1167,6 +1226,17 @@ private: myMap->resetMap(width, height); } + void handleStation(const AttributeSet& attrs) + { + myActiveStation = makeStation(); + + int id; + attrs.get("id", id); + myActiveStation->setId(id); + + myStations[id] = myActiveStation; + } + void handleStart(const AttributeSet& attrs) { int x, y, dirX, dirY; @@ -1184,6 +1254,19 @@ private: attrs.get("y", myYPtr); } + void handleStationPart(const AttributeSet& attrs) + { + int id; + attrs.get("id", id); + + map::iterator it = myStations.find(id); + if (it == myStations.end()) + throw runtime_error("No station definition for ID " + + boost::lexical_cast(id)); + else + myMap->setStationAt(myXPtr, myYPtr, (*it).second); + } + void handleStraightTrack(const AttributeSet& attrs) { string align; @@ -1213,6 +1296,8 @@ private: } shared_ptr myMap; + map myStations; + IStationPtr myActiveStation; int myXPtr, myYPtr; }; diff --git a/src/Station.cpp b/src/Station.cpp index cd81144..a3f005b 100644 --- a/src/Station.cpp +++ b/src/Station.cpp @@ -31,6 +31,8 @@ public: // IStation interface const string& name() const { return myName; } void setName(const string& aName) { myName = aName; } + int id() const { return myId; } + void setId(int anId) { myId = anId; } HighlightColour highlightColour() const { return myColour; } bool highlightVisible() const { return isHighlightVisible; } void setHighlightVisible(bool onOff); @@ -38,6 +40,7 @@ private: string myName; HighlightColour myColour; bool isHighlightVisible; + int myId; }; Station::Station() @@ -47,7 +50,8 @@ Station::Station() // Generate a unique station name; static int nameCounter = 1; - myName = "Station" + lexical_cast(nameCounter++); + myId = nameCounter++; + myName = "Station" + lexical_cast(myId); // Generate a random colour static variate_generator > diff --git a/src/XMLParser.cpp b/src/XMLParser.cpp index 2959e35..427846a 100644 --- a/src/XMLParser.cpp +++ b/src/XMLParser.cpp @@ -67,6 +67,8 @@ struct SAX2WrapperHandler : public DefaultHandler { callbackPtr->text(chLocalname, charBuf.str()); charBuf.str(""); } + + callbackPtr->endElement(chLocalname); XMLString::release(&chLocalname); } -- 2.39.2