The open source repository for the action RPG game in development by Sig Productions titled 'Adventures in Lestoria'! https://forums.lestoria.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AdventuresInLestoria/Crawler/TSXParser.h

173 lines
6.5 KiB

#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
extern bool _DEBUG_MAP_LOAD_INFO;
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==' '&&quotationMarkCount%2==0){
valid=true;
break;
}
data+=character;
if(pastEquals&&quotationMarkCount%2==0){
valid=true;
break;
}
if(character=='='&&quotationMarkCount%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;
if(_DEBUG_MAP_LOAD_INFO)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;
if(_DEBUG_MAP_LOAD_INFO)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)){
if(_DEBUG_MAP_LOAD_INFO)std::cout<<"WARNING! There was already collision data defined for tile "<<previousTagID<<"!"<<std::endl;
throw;
}
parsedTilesetInfo.CollisionData[previousTagID]=data;
}
if(_DEBUG_MAP_LOAD_INFO)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!
}
}
}
if(_DEBUG_MAP_LOAD_INFO)std::cout<<"Parsed Tileset Data:\n"<<parsedTilesetInfo<<"\n";
}
#endif