#pragma once #include "olcPixelGameEngine.h" #include <sstream> #include "TMXParser.h" #include "Map.h" #include "olcUTIL_Geometry2D.h" #include "olcUTIL_DataFile.h" using namespace olc; struct Tileset{ XMLTag ImageData; std::map<int,XMLTag> ForegroundTileData; std::map<int,XMLTag> UpperForegroundTileData; std::map<int,TileCollisionData> CollisionData; std::map<int,XMLTag> StaircaseData; std::map<int,std::vector<int>> AnimationData; std::set<int> ReflectiveData; friend std::ostream& operator << (std::ostream& os, Tileset& rhs); }; class TSXParser{ public: Tileset&GetData(); private: Tileset parsedTilesetInfo; void ParseTag(std::string tag); std::string previousTag; int previousTagID; std::string staircaseTag=""; public: TSXParser(std::string file); }; #ifdef TSX_PARSER_SETUP #undef TSX_PARSER_SETUP Tileset&TSXParser::GetData() { return parsedTilesetInfo; } std::ostream&operator<<(std::ostream& os, Tileset& rhs){ os<<rhs.ImageData.FormatTagData(rhs.ImageData.data)<<"\n"; return os; } void TSXParser::ParseTag(std::string tag) { XMLTag newTag; //First character is a '<' so we discard it. tag.erase(0,1); tag.erase(tag.length()-1,1); //Erase the first and last characters in the tag. Now parse by spaces. std::stringstream s(tag); //Turn it into a string stream to now parse into individual whitespaces. std::string data; while (s.good()) { int quotationMarkCount=0; bool pastEquals=false; data=""; bool valid=false; while(s.good()){ int character=s.get(); if(character=='"'){ quotationMarkCount++; } if(character==' '&"ationMarkCount%2==0){ valid=true; break; } data+=character; if(pastEquals&"ationMarkCount%2==0){ valid=true; break; } if(character=='='&"ationMarkCount%2==0){ pastEquals=true; } } if(valid&&data.length()>0){ if (newTag.tag.length()==0) { //Tag's empty, so first line is the tag. newTag.tag=data; std::cout<<"Tag: "<<newTag.tag<<"\n"; } else { std::string key = data.substr(0,data.find("=")); std::string value = data.substr(data.find("=")+1,std::string::npos); //Strip Quotation marks. value = value.substr(1,std::string::npos); value = value.substr(0,value.length()-1); newTag.data[key]=value; std::cout<<" "<<key<<":"<<newTag.data[key]<<"\n"; } } } if (newTag.tag=="image") { parsedTilesetInfo.ImageData=newTag; } else if (newTag.tag=="tile"&&newTag.data["type"]=="ForegroundTile"){ previousTag=newTag.tag; previousTagID=newTag.GetInteger("id"); parsedTilesetInfo.ForegroundTileData[newTag.GetInteger("id")]=newTag; } else if (newTag.tag=="tile"&&newTag.data["type"]=="UpperForegroundTile"){ previousTag=newTag.tag; previousTagID=newTag.GetInteger("id"); parsedTilesetInfo.UpperForegroundTileData[newTag.GetInteger("id")]=newTag; } else if (newTag.tag=="tile"&&newTag.data["type"]=="Staircase"){ previousTag=newTag.tag; staircaseTag=newTag.tag; previousTagID=newTag.GetInteger("id"); } else if (newTag.tag=="tile"&&newTag.data["type"]=="Reflective"){ previousTag=newTag.tag; previousTagID=newTag.GetInteger("id"); parsedTilesetInfo.ReflectiveData.insert(newTag.GetInteger("id")); } else if (newTag.tag=="tile"){ previousTag=newTag.tag; previousTagID=newTag.GetInteger("id"); } else if (newTag.tag=="frame"){ //The way animation data is stored is every "animation_tile_precision" ms indicating which frame we should be on. for(int i=0;i<newTag.GetInteger("duration")/"animation_tile_precision"_I;i++){ parsedTilesetInfo.AnimationData[previousTagID].push_back(newTag.GetInteger("tileid")); } } else if (newTag.tag=="property"&&staircaseTag=="tile"){ parsedTilesetInfo.StaircaseData[previousTagID]=newTag; staircaseTag=""; } else if (newTag.tag=="object"&&previousTag=="tile"){ TileCollisionData data; data.collision=geom2d::rect<int>{{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}}; if(parsedTilesetInfo.CollisionData.count(previousTagID)){ std::cout<<"WARNING! There was already collision data defined for tile "<<previousTagID<<"!"<<std::endl; throw; } parsedTilesetInfo.CollisionData[previousTagID]=data; } std::cout<<"\n"<<"=============\n"; } TSXParser::TSXParser(std::string file) :previousTagID(-1){ std::ifstream f(file,std::ios::in); std::string accumulator=""; while (f.good()) { std::string data; f>>data; if (data.empty()) continue; if (accumulator.length()>0) { accumulator+=" "+data; //Check if it ends with '>' if (data[data.length()-1]=='>') { ParseTag(accumulator); accumulator=""; } } else if (data[0]=='<') { //Beginning of XML tag. accumulator=data; if(accumulator.length()>1&&accumulator.at(1)=='/'){ accumulator=""; //Restart because this is an end tag. } if(accumulator.length()>1&&accumulator.find('>')!=std::string::npos){ accumulator=""; //Restart because this tag has nothing in it! } } } std::cout<<"Parsed Tileset Data:\n"<<parsedTilesetInfo<<"\n"; } #endif