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/TMXParser.h

291 lines
10 KiB

#pragma once
#include "olcPixelGameEngine.h"
#include "olcUTIL_Geometry2D.h"
#include <strstream>
using namespace olc;
struct XMLTag{
std::string tag;
std::map<std::string,std::string> data;
const std::string FormatTagData(std::map<std::string,std::string>tiles);
friend std::ostream& operator << (std::ostream& os, XMLTag& rhs);
std::string str();
int GetInteger(std::string dataTag);
float GetFloat(std::string dataTag);
double GetDouble(std::string dataTag);
bool GetBool(std::string dataTag);
};
struct MapTag{
int width,height;
vi2d playerSpawnLocation;
friend std::ostream& operator << (std::ostream& os, MapTag& rhs);
};
struct LayerTag{
XMLTag tag;
std::vector<std::vector<int>> tiles;
std::string str();
};
struct SpawnerTag{
XMLTag ObjectData;
std::vector<XMLTag>properties;
std::string str();
friend std::ostream& operator << (std::ostream& os, SpawnerTag& rhs);
};
struct Map{
MapTag MapData;
std::vector<XMLTag> TilesetData;
std::vector<LayerTag> LayerData;
std::vector<SpawnerTag> SpawnerData;
std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
std::string FormatLayerData(std::ostream& os, std::vector<LayerTag>tiles);
std::string FormatSpawnerData(std::ostream& os, std::vector<SpawnerTag>tiles);
friend std::ostream& operator << (std::ostream& os, Map& rhs);
friend std::ostream& operator << (std::ostream& os, std::vector<XMLTag>& rhs);
};
class TMXParser{
public:
Map GetData();
private:
Map parsedMapInfo;
bool buildingSpawner=false;
SpawnerTag obj;
void ParseTag(std::string tag);
public:
TMXParser(std::string file);
};
#ifdef TMX_PARSER_SETUP
#undef TMX_PARSER_SETUP
const std::string XMLTag::FormatTagData(std::map<std::string,std::string>tiles){
std::string displayStr="";
for (std::map<std::string,std::string>::iterator it=data.begin();it!=data.end();it++) {
displayStr+=" "+it->first+": "+it->second+"\n";
}
return displayStr;
}
std::ostream& operator << (std::ostream& os, XMLTag& rhs){
os <<
rhs.tag <<"\n"<<
rhs.FormatTagData(rhs.data) <<"\n";
return os;
}
std::ostream& operator << (std::ostream& os, MapTag& rhs){
os <<
"(width:"<<rhs.width<<", height:"<<rhs.height<<",playerSpawnLocation:"<<rhs.playerSpawnLocation<<")\n";
return os;
}
int XMLTag::GetInteger(std::string dataTag) {
return std::stoi(data[dataTag]);
}
float XMLTag::GetFloat(std::string dataTag) {
return std::stof(data[dataTag]);
}
double XMLTag::GetDouble(std::string dataTag) {
return std::stod(data[dataTag]);
}
bool XMLTag::GetBool(std::string dataTag) {
if (data[dataTag]=="0") {
return false;
} else {
return true;
}
}
std::string XMLTag::str() {
return tag+"\n";
}
std::string LayerTag::str() {
std::string displayStr=tag.tag+"\n"+tag.FormatTagData(tag.data);
displayStr+=" DATA ("+std::to_string(tiles[0].size())+"x"+std::to_string(tiles.size())+" )\n";
return displayStr;
}
std::string SpawnerTag::str() {
std::string displayStr=ObjectData.tag+"\n"+ObjectData.FormatTagData(ObjectData.data);
for(XMLTag tag:properties){
displayStr+=" ("+tag.FormatTagData(tag.data)+" )\n";
}
return displayStr;
}
std::ostream& operator << (std::ostream& os, SpawnerTag& rhs) {
os << rhs.str()<<"\n";
return os;
}
std::string Map::FormatLayerData(std::ostream& os, std::vector<LayerTag>tiles) {
std::string displayStr;
for (int i=0;i<LayerData.size();i++) {
displayStr+=LayerData[i].str();
}
return displayStr;
}
std::string Map::FormatSpawnerData(std::ostream& os, std::vector<SpawnerTag>tiles) {
std::string displayStr;
for (int i=0;i<SpawnerData.size();i++) {
displayStr+=SpawnerData[i].str();
}
return displayStr;
}
std::ostream& operator <<(std::ostream& os, std::vector<XMLTag>& rhs) {
for(XMLTag&tag:rhs){
os <<
tag<<"\n";
}
return os;
}
std::ostream& operator <<(std::ostream& os, Map& rhs) {
os <<
rhs.MapData <<"\n"<<
rhs.TilesetData <<"\n"<<
rhs.FormatLayerData(os,rhs.LayerData) <<"\n"<<
rhs.FormatSpawnerData(os,rhs.SpawnerData)<<"\n";
return os;
}
Map TMXParser::GetData() {
return parsedMapInfo;
}
void TMXParser::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;
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=="map") {
parsedMapInfo.MapData={stoi(newTag.data["width"]),stoi(newTag.data["height"])};
} else
if (newTag.tag=="tileset") {
parsedMapInfo.TilesetData.push_back(newTag);
} else
if (newTag.tag=="layer") {
LayerTag l = {newTag};
parsedMapInfo.LayerData.push_back(l);
}else
if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup") {
if(buildingSpawner){
parsedMapInfo.SpawnerData.push_back(obj);
}
buildingSpawner=true;
obj={newTag};
goto spawnerResetSkip;
} else
if (newTag.tag=="object"&&newTag.data["type"]=="PlayerSpawnLocation") {
parsedMapInfo.MapData.playerSpawnLocation={newTag.GetInteger("x")-newTag.GetInteger("width")/2,newTag.GetInteger("y")-newTag.GetInteger("height")/2};
} else
if (newTag.tag=="object"&&newTag.data.find("type")!=newTag.data.end()){
//This is an object with a type that doesn't fit into other categories, we can add it to ZoneData.
if(parsedMapInfo.ZoneData.find(newTag.data["type"])!=parsedMapInfo.ZoneData.end()){
std::vector<geom2d::rect<int>>&zones=parsedMapInfo.ZoneData[newTag.data["type"]];
zones.push_back({{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}});
} else {
std::vector<geom2d::rect<int>>zones;
zones.push_back({{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}});
parsedMapInfo.ZoneData[newTag.data["type"]]=zones;
}
}
if (newTag.tag=="property"&&buildingSpawner) {
if(newTag.data["propertytype"]=="MonsterName"){
obj.properties.push_back(newTag);
}
goto spawnerResetSkip;
} else {
std::cout<<"Unsupported tag format! Ignoring."<<"\n";
}
if(buildingSpawner){
parsedMapInfo.SpawnerData.push_back(obj);
}
buildingSpawner=false;
spawnerResetSkip:
std::cout<<"\n"<<"=============\n";
}
TMXParser::TMXParser(std::string file){
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!
}
} else {
//Start reading in data for this layer.
std::vector<int>rowData;
while (data.find(",")!=std::string::npos) {
std::string datapiece = data.substr(0,data.find(","));
data = data.substr(data.find(",")+1,std::string::npos);
rowData.push_back(stoi(datapiece));
}
if (data.length()) {
rowData.push_back(stoi(data));
}
parsedMapInfo.LayerData[parsedMapInfo.LayerData.size()-1].tiles.push_back(rowData);
}
}
if(buildingSpawner){
parsedMapInfo.SpawnerData.push_back(obj);
}
std::cout<<"Parsed Map Data:\n"<<parsedMapInfo<<"\n";
}
#endif