Add in missing parsing features for TSX reading so that we have all the information we need to recreate the file.

master
sigonasr2 8 months ago
parent 5255502945
commit a70e604c62
  1. 116
      TiledCollisionEditor/Error.h
  2. 77
      TiledCollisionEditor/TSXParser.h
  3. 4
      TiledCollisionEditor/TiledCollisionEditor.vcxproj
  4. 3
      TiledCollisionEditor/TiledCollisionEditor.vcxproj.filters
  5. 6
      TiledCollisionEditor/Tiles/Basic Tileset.tsx
  6. 1
      TiledCollisionEditor/Tileset.h
  7. 5
      TiledCollisionEditor/main.cpp
  8. 22
      assets/Tiles/Basic Tileset.tsx

@ -0,0 +1,116 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#include <iostream>
#include <sstream>
#include <format>
#include <any>
#include <memory>
#include <source_location>
#ifdef _DEBUG
#ifndef __EMSCRIPTEN__
#ifndef __linux__
#define NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
// allocations to be of _CLIENT_BLOCK type
#else
#define NEW new
#endif
#else
#define NEW new
#endif
#else
#define NEW new
#endif
#undef ERR //Stupid Windows
#ifndef __EMSCRIPTEN__
//WARNING! err accepts a stream of data using << operators. If you want to concatenate strings via the + operator, you must wrap the entire operation in ()
#define ERR(err) { \
std::stringstream errStream; \
errStream<<err; \
Error::log(errStream,std::source_location::current());}
class Error{
public:
inline static void log(std::stringstream&str,std::source_location loc){
std::cout<<loc.file_name()<<"("<<loc.line()<<":"<<loc.column()<<") "<<loc.function_name()<<": "<<str.str()<<std::endl;
throw;
}
};
#else
#define ERR(err) { \
std::stringstream errStream; \
errStream<<err; \
Error::log(errStream,std::source_location::current());}
class Error{
public:
inline static void log(std::stringstream&str,std::source_location loc){
std::cout<<loc.file_name()<<"("<<loc.line()<<":"<<loc.column()<<") "<<loc.function_name()<<": "<<str.str()<<std::endl;
#ifdef __DEBUG__
throw;
#endif
}
};
#define _CrtDumpMemoryLeaks() ((int)0)
#endif
template<typename type>
type DYNAMIC_CAST(auto variable){
type pointer=dynamic_cast<type>(variable);
if(pointer==nullptr)ERR("Could not dynamic cast to type "<<typeid(variable).name()<<"!");
return pointer;
}
template<typename T,typename U>
std::shared_ptr<T>DYNAMIC_POINTER_CAST(const std::shared_ptr<U>&variable){
std::shared_ptr<T> newVariable=dynamic_pointer_cast<T>(variable);
if(!newVariable)ERR("Could not dynamic cast to pointer type "<<typeid(newVariable).name()<<"!");
return newVariable;
}
template<typename T,typename U>
std::shared_ptr<T>DYNAMIC_POINTER_CAST(const std::weak_ptr<U>&variable){
std::shared_ptr<T> newVariable=dynamic_pointer_cast<T>(variable.lock());
if(!newVariable)ERR("Could not dynamic cast to pointer type "<<typeid(newVariable).name()<<"!");
return newVariable;
}

@ -43,6 +43,7 @@ All rights reserved.
#include "olcUTIL_Geometry2D.h" #include "olcUTIL_Geometry2D.h"
#include "Tileset.h" #include "Tileset.h"
#include "Error.h"
using namespace olc; using namespace olc;
using namespace olc::utils; using namespace olc::utils;
@ -53,8 +54,24 @@ class TSXParser{
return parsedTilesetInfo; return parsedTilesetInfo;
} }
private: private:
class NonObject{
public:
std::vector<XMLTag>tags;
};
enum NextObjectType{
OBJECT,
PERSPECTIVEOBJECT,
NONOBJECT,
};
Tileset parsedTilesetInfo; Tileset parsedTilesetInfo;
std::vector<XMLTag>originalData;
std::vector<NonObject>nonObjects;
int previousTagID; int previousTagID;
std::string currentObj;
NextObjectType nextObjType;
inline void ParseTag(std::string tag){ inline void ParseTag(std::string tag){
XMLTag newTag; XMLTag newTag;
//First character is a '<' so we discard it. //First character is a '<' so we discard it.
@ -99,27 +116,77 @@ class TSXParser{
} }
} }
} }
//objectgroup
//object
//polygon
if (newTag.tag=="tileset") { if (newTag.tag=="tileset") {
parsedTilesetInfo.name=newTag.data["name"];
parsedTilesetInfo.tilecount=stoi(newTag.data["tilecount"]); parsedTilesetInfo.tilecount=stoi(newTag.data["tilecount"]);
parsedTilesetInfo.tilewidth=stoi(newTag.data["tilewidth"]); parsedTilesetInfo.tilewidth=stoi(newTag.data["tilewidth"]);
parsedTilesetInfo.tileheight=stoi(newTag.data["tileheight"]); parsedTilesetInfo.tileheight=stoi(newTag.data["tileheight"]);
parsedTilesetInfo.columns=stoi(newTag.data["columns"]); parsedTilesetInfo.columns=stoi(newTag.data["columns"]);
} else }else
if (newTag.tag=="image") { if (newTag.tag=="image") {
parsedTilesetInfo.ImageData=newTag; parsedTilesetInfo.ImageData=newTag;
parsedTilesetInfo.filename=newTag.GetString("source"); parsedTilesetInfo.filename=newTag.GetString("source");
parsedTilesetInfo.imagewidth=newTag.GetInteger("width"); parsedTilesetInfo.imagewidth=newTag.GetInteger("width");
parsedTilesetInfo.imageheight=newTag.GetInteger("height"); parsedTilesetInfo.imageheight=newTag.GetInteger("height");
} else }else
if (newTag.tag=="property"){ if (newTag.tag=="property"){
if(nextObjType!=NONOBJECT){
if(newTag.data["name"]=="Name"){ if(newTag.data["name"]=="Name"){
std::string objectName=newTag.data["value"]; std::string objectName=newTag.data["value"];
currentObj=objectName;
parsedTilesetInfo.objects[objectName].AddTile(parsedTilesetInfo,previousTagID); parsedTilesetInfo.objects[objectName].AddTile(parsedTilesetInfo,previousTagID);
} parsedTilesetInfo.objects[objectName].perspectiveObj=nextObjType==PERSPECTIVEOBJECT;
} else }
}else{
nonObjects.back().tags.push_back(newTag);
}
}else
if (newTag.tag=="object"){
if(newTag.GetInteger("x")!=0||newTag.GetInteger("y")!=0){
ERR(std::format("WARNING! The collision for {} was not properly made inside of this editor, but in Tiled!\n\nTHIS IS NOT ALLOWED!\n\nPlease delete the collision for {} to modify it here (Tileset ID: {}) \n\nCollision X:{} Collision Y:{}",currentObj,currentObj,previousTagID,newTag.GetInteger("x"),newTag.GetInteger("y")));
}
}else
if (newTag.tag=="polygon"){
int pointCount=0;
size_t parseMarker=0;
bool findComma=true;
vf2d collision;
Quadrilateral collisionQuad;
const std::string points=newTag.GetString("points");
while(parseMarker<points.length()){
size_t currentMarker=parseMarker;
if(findComma){
collision.x=std::stof(points.substr(currentMarker,(parseMarker=points.find(',',currentMarker))-currentMarker));
}else{
collision.y=std::stof(points.substr(currentMarker,(parseMarker=points.find(' ',currentMarker))-currentMarker));
if(pointCount>3)ERR("WARNING! Trying to parse a shape that has more than 4 sides!");
collisionQuad[pointCount++]=collision;
}
if(parseMarker==std::string::npos)break;
parseMarker++; //Ignore the symbol
findComma=!findComma;
}
if(pointCount<3)ERR("WARNING! Trying to parse a shape that has less than 4 sides!");
parsedTilesetInfo.objects[currentObj].collisionTiles.push_back(collisionQuad);
}else
if (newTag.tag=="tile"){ if (newTag.tag=="tile"){
if(newTag.data["type"]=="Object"){
nextObjType=OBJECT;
}else
if(newTag.data["type"]=="PerspectiveObject"){
nextObjType=PERSPECTIVEOBJECT;
}else{
nextObjType=NONOBJECT;
nonObjects.push_back({});
nonObjects.back().tags.push_back(newTag);
}
previousTagID=newTag.GetInteger("id"); previousTagID=newTag.GetInteger("id");
}else
{
originalData.push_back(newTag);
} }
}; };
public: public:

@ -129,6 +129,10 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Error.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="olcPGEX_QuickGUI.h"> <ClInclude Include="olcPGEX_QuickGUI.h">
<SubType> <SubType>
</SubType> </SubType>

@ -48,6 +48,9 @@
<ClInclude Include="olcPGEX_ViewPort.h"> <ClInclude Include="olcPGEX_ViewPort.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Error.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">

@ -722,6 +722,12 @@
<property name="Name" value="BlueHouse1"/> <property name="Name" value="BlueHouse1"/>
</properties> </properties>
</tile> </tile>
<tile id="257" type="TestClass">
<properties>
<property name="TestNumber" type="int" value="10"/>
<property name="TestProperty" value="Testing"/>
</properties>
</tile>
<tile id="264" type="PerspectiveObject"> <tile id="264" type="PerspectiveObject">
<properties> <properties>
<property name="Name" value="BlueHouse1"/> <property name="Name" value="BlueHouse1"/>

@ -43,6 +43,7 @@ All rights reserved.
struct Tileset{ struct Tileset{
std::string filename; std::string filename;
std::string name;
std::unordered_map<std::string,TilesetObject>objects; std::unordered_map<std::string,TilesetObject>objects;
XMLTag ImageData; XMLTag ImageData;
int tilecount=0; int tilecount=0;

@ -44,7 +44,7 @@ public:
ImageCheckBox*createNewButton=nullptr; ImageCheckBox*createNewButton=nullptr;
ImageCheckBox*editButton=nullptr; ImageCheckBox*editButton=nullptr;
TSXParser parsedMap{""};
public: public:
bool OnUserCreate() override bool OnUserCreate() override
{ {
@ -61,7 +61,8 @@ public:
editButtonImg.Load("EditButton.png"); editButtonImg.Load("EditButton.png");
std::string tilesetFilename=TILESET_DIR+"Basic Tileset.tsx"; std::string tilesetFilename=TILESET_DIR+"Basic Tileset.tsx";
Tileset&tileset=tilesets[tilesetFilename]=TSXParser{tilesetFilename}.GetData(); parsedMap={tilesetFilename};
Tileset&tileset=tilesets[tilesetFilename]=parsedMap.GetData();
Renderable&tilesetImg=images[tilesetFilename]; Renderable&tilesetImg=images[tilesetFilename];
tilesetImg.Load(TILESET_DIR+tileset.filename); tilesetImg.Load(TILESET_DIR+tileset.filename);

@ -6,6 +6,11 @@
<properties> <properties>
<property name="Name" value="Stop Sign"/> <property name="Name" value="Stop Sign"/>
</properties> </properties>
<objectgroup draworder="index" id="2">
<object id="1" x="0" y="0">
<polygon points="-5,-55 20,-80 50,-59 25,27"/>
</object>
</objectgroup>
</tile> </tile>
<tile id="4" type="Object"> <tile id="4" type="Object">
<properties> <properties>
@ -16,6 +21,17 @@
<properties> <properties>
<property name="Name" value="BlueHouse1"/> <property name="Name" value="BlueHouse1"/>
</properties> </properties>
<objectgroup draworder="index" id="2">
<object id="1" x="-33" y="31">
<polygon points="0,0 12,20 -25,35 -30,2"/>
</object>
<object id="2" x="-33" y="31">
<polygon points="0,0 29,-17 45,4 12,20"/>
</object>
<object id="3" x="-21" y="51">
<polygon points="0,0 33,-16 45,28 1,25"/>
</object>
</objectgroup>
</tile> </tile>
<tile id="9" type="PerspectiveObject"> <tile id="9" type="PerspectiveObject">
<properties> <properties>
@ -722,6 +738,12 @@
<property name="Name" value="BlueHouse1"/> <property name="Name" value="BlueHouse1"/>
</properties> </properties>
</tile> </tile>
<tile id="257" type="TestClass">
<properties>
<property name="TestNumber" type="int" value="10"/>
<property name="TestProperty" value="Testing"/>
</properties>
</tile>
<tile id="264" type="PerspectiveObject"> <tile id="264" type="PerspectiveObject">
<properties> <properties>
<property name="Name" value="BlueHouse1"/> <property name="Name" value="BlueHouse1"/>

Loading…
Cancel
Save