broke apart EntityConverter::convert, added submodule

This commit is contained in:
suhrke 2017-07-02 20:22:09 -07:00
parent 757daa6dd1
commit 225e1375ef
7 changed files with 410 additions and 211 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "ReflexToQ3/includes/cxxopts"]
path = ReflexToQ3/includes/cxxopts
url = https://github.com/jarro2783/cxxopts.git

View File

@ -6,4 +6,4 @@
*.log *.log
# executables # executables
reflex2q3_* reflex2q3

View File

@ -1,9 +1,9 @@
EX=reflex2q3 EX=reflex2q3
CC=g++ CC=g++
CFLAGS=-std=c++11 -I"includes" -I"/usr/include/eigen3" CFLAGS=-std=c++11 -I"./includes" -I"./includes/cxxopts/include" -I"/usr/include/eigen3"
TESTEX=test/test-parser TESTEX=test/test-parser
all: main test all: main
main: planes.o brushdef.o oopless-parser.o EntityConverter.o main: planes.o brushdef.o oopless-parser.o EntityConverter.o
$(CC) $^ main.cpp $(CFLAGS) -o $(EX) 2>error8.log $(CC) $^ main.cpp $(CFLAGS) -o $(EX) 2>error8.log

View File

@ -24,44 +24,36 @@
/*-----------------------------------------------------------------------------
* PUBLIC
*-----------------------------------------------------------------------------*/
EntityConverter::EntityConverter(std::string entityMapFile)
{
//MUST RUN matchRelated method after this constructor
areEntitiesMatched_ = false;
mapEntities(entityMapFile);
}
EntityConverter::EntityConverter(std::string entityMapFile, std::string reflexMapFile) EntityConverter::EntityConverter(std::string entityMapFile, std::string reflexMapFile)
{ {
//Open .ent mapping file mapEntities(entityMapFile);
std::ifstream entFin;
entFin.open(entityMapFile);
if ( entFin.is_open() ) { // Pre-scan for related entities
//Read .ent contents into pickup map std::ifstream fin;
std::string line; fin.open(reflexMapFile);
while (std::getline(entFin, line)) {
std::istringstream iss(line);
// Reflex ID corresponds to xonotic pickup name
int id;
std::string pickup;
if ( ! (iss >> id >> pickup)) {
throw std::runtime_error( "format error in .ent file" );
}
pickupMapping_.insert ( std::pair<int, std::string>(id, pickup) );
}
}
else {
throw std::ios::failure( "Error: EntityConverter failed to open .ent file" );
}
entFin.close();
if ( fin.is_open() ) {
//Open .map file
std::ifstream mapFin;
mapFin.open(reflexMapFile);
if ( mapFin.is_open() ) {
//Extract the source type of targets (teleporters or jump pads) //Extract the source type of targets (teleporters or jump pads)
std::string line; std::string line;
std::string trash; std::string trash;
std::string targetName; std::string targetName;
while (std::getline(mapFin, line)) { while (std::getline(fin, line)) {
if ( line.find("type Teleporter") != std::string::npos) { if ( line.find("type Teleporter") != std::string::npos) {
std::getline(mapFin, line); std::getline(fin, line);
std::istringstream iss(line); std::istringstream iss(line);
if ( ! (iss >> trash >> trash >> targetName)) { if ( ! (iss >> trash >> trash >> targetName)) {
throw std::runtime_error( "format error in .map file"); throw std::runtime_error( "format error in .map file");
@ -69,7 +61,7 @@ EntityConverter::EntityConverter(std::string entityMapFile, std::string reflexMa
targetMap_.insert ( std::pair<std::string, std::string>(targetName, "Teleporter") ); targetMap_.insert ( std::pair<std::string, std::string>(targetName, "Teleporter") );
} }
else if ( line.find("type JumpPad") != std::string::npos) { else if ( line.find("type JumpPad") != std::string::npos) {
std::getline(mapFin, line); std::getline(fin, line);
std::istringstream iss(line); std::istringstream iss(line);
if ( ! (iss >> trash >> trash >> targetName)) { if ( ! (iss >> trash >> trash >> targetName)) {
throw std::runtime_error( "format error in .map file"); throw std::runtime_error( "format error in .map file");
@ -81,7 +73,8 @@ EntityConverter::EntityConverter(std::string entityMapFile, std::string reflexMa
else { else {
throw std::ios::failure( "Error: EntityConverter failed to open .map file" ); throw std::ios::failure( "Error: EntityConverter failed to open .map file" );
} }
mapFin.close(); fin.close();
areEntitiesMatched_ = true;
//DEBUG //DEBUG
//printMapping(); //printMapping();
@ -89,24 +82,61 @@ EntityConverter::EntityConverter(std::string entityMapFile, std::string reflexMa
} }
// DEBUG
void EntityConverter::printMapping()
{
std::map<int, std::string>::iterator it;
for (it=pickupMapping_.begin(); it!=pickupMapping_.end(); ++it)
std::cout << it->first << " => " << it->second << std::endl;
}
// DEBUG std::vector<std::string>
void EntityConverter::printTargetSources() EntityConverter::convert(std::vector<std::string> lines)
{ {
std::map<std::string, std::string>::iterator it; if ( areEntitiesMatched_ )
for (it=targetMap_.begin(); it!=targetMap_.end(); ++it) {
std::cout << it->first << " => " << it->second << std::endl; std::string attribute;
std::string trash; //unused tokens
std::string type;
if ( lines.size() < 1 ) {
throw std::runtime_error("error: empty entity cannot be converted");
}
// second token is the type
std::istringstream iss(lines[0]);
if ( ! (iss >> trash >> type)) {
throw std::runtime_error("error: type is required");
} }
std::string EntityConverter::getAttributeType(std::string line) if ( type == "Pickup" ) {
return convertPickup(lines);
}
else if ( type == "PlayerSpawn" ) {
return convertPlayerSpawn(lines);
}
else if ( type == "JumpPad" ) {
return convertJumpPad(lines);
}
else if ( type == "Teleporter" ) {
return convertTeleporter(lines);
}
else if ( type == "Target" ) {
return convertTarget(lines);
}
else if ( type == "RaceStart" ) {
return convertRaceStart(lines);
}
else if ( type == "RaceFinish" ) {
return convertRaceFinish(lines);
}
}
else {
throw std::runtime_error( "error: related entities must be matched prior to conversion" );
}
}
/*-----------------------------------------------------------------------------
* PRIVATE
*-----------------------------------------------------------------------------*/
std::string
EntityConverter::getAttributeType(std::string line)
{ {
std::string type; std::string type;
std::string dataType; std::string dataType;
@ -120,29 +150,44 @@ std::string EntityConverter::getAttributeType(std::string line)
std::vector<std::string> EntityConverter::convert(std::vector<std::string> lines) void
EntityConverter::mapEntities(std::string mapFile)
{
std::ifstream fin;
fin.open(mapFile);
if ( fin.is_open() ) {
//Read .ent contents into pickup map
std::string line;
while (std::getline(fin, line)) {
std::istringstream iss(line);
// Reflex ID corresponds to xonotic pickup name
int id;
std::string pickup;
if ( ! (iss >> id >> pickup)) {
throw std::runtime_error( "format error in .ent file" );
}
pickupMapping_.insert ( std::pair<int, std::string>(id, pickup) );
}
}
else {
throw std::ios::failure( "Error: EntityConverter failed to open .ent file" );
}
fin.close();
}
std::vector<std::string>
EntityConverter::convertPickup(std::vector<std::string> &lines)
{ {
std::vector<std::string> convertedLines; std::vector<std::string> convertedLines;
std::string coords[3]; std::string coords[3];
std::string attribute; std::string trash;
std::string trash; //unused tokens
std::string type;
if ( lines.size() < 1 ) {
std::cerr << "error: empty entity cannot be converted" << std::endl;
return convertedLines;
}
// second token is the type
std::istringstream iss(lines[0]);
if ( ! (iss >> trash >> type)) {
std::cerr << "error: type is required" << std::endl;
return convertedLines;
}
if ( type == "Pickup" ) { ////PICKUP
if ( lines.size() < 3 ) { if ( lines.size() < 3 ) {
std::cerr << "error: Pickup entity requires at least 3 lines" << std::endl; throw std::runtime_error("error: Pickup entity requires at least 3 lines");
return convertedLines;
} }
//can ignore angle of pickups in xonotic format //can ignore angle of pickups in xonotic format
int pickupID; int pickupID;
@ -150,23 +195,21 @@ std::vector<std::string> EntityConverter::convert(std::vector<std::string> lines
bool havePickupID = false; bool havePickupID = false;
for (int i = 1; i < lines.size(); i++) { for (int i = 1; i < lines.size(); i++) {
type = getAttributeType(lines[i]); std::string type = getAttributeType(lines[i]);
if ( type == "position" ) { if ( type == "position" ) {
std::istringstream iss2(lines[i]); std::istringstream iss(lines[i]);
// Vector3 position coord0 coord1 coord2 // Vector3 position coord0 coord1 coord2
if ( ! (iss2 >> trash >> trash >> if ( ! (iss >> trash >> trash >>
coords[0] >> coords[1] >> coords[2])) { coords[0] >> coords[1] >> coords[2])) {
std::cerr << "error: Pickup entity requires coordinates" << std::endl; throw std::runtime_error("error: Pickup entity requires coordinates");
return convertedLines;
} }
havePosition = true; havePosition = true;
} }
else if ( type == "pickupType" ) { else if ( type == "pickupType" ) {
std::istringstream iss2(lines[i]); std::istringstream iss(lines[i]);
// UInt8 pickupType ID // UInt8 pickupType ID
if ( ! (iss2 >> trash >> trash >> pickupID) ) { if ( ! (iss >> trash >> trash >> pickupID) ) {
std::cerr << "error: Pickup entity requires pickup ID" << std::endl; throw std::runtime_error("error: Pickup entity requires Pickup ID");
return convertedLines;
} }
havePickupID = true; havePickupID = true;
} }
@ -181,36 +224,62 @@ std::vector<std::string> EntityConverter::convert(std::vector<std::string> lines
oss2 << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << oss2 << "\"origin\" \"" << coords[0] << " " << coords[2] << " " <<
coords[1] << "\"" << std::endl; coords[1] << "\"" << std::endl;
convertedLines.push_back ( oss2.str() ); convertedLines.push_back ( oss2.str() );
return convertedLines;
}
else {
throw std::runtime_error("error: Pickup requires position and pickup ID, missing 1 or both");
} }
} }
else if ( type == "PlayerSpawn" ) { ///PLAYER SPAWN
std::vector<std::string>
EntityConverter::convertPlayerSpawn(std::vector<std::string> &lines)
{
//minimum of 3 lines, max of ? lines //minimum of 3 lines, max of ? lines
std::istringstream iss2(lines[1]);
} }
else if ( type == "JumpPad" ) { ///JUMP PAD
std::vector<std::string>
EntityConverter::convertJumpPad(std::vector<std::string> &lines)
{
std::vector<std::string> convertedLines;
std::string trash;
if ( lines.size() < 2 ) { if ( lines.size() < 2 ) {
std::cerr << "error: JumpPad entity requires at least 2 lines" << std::endl; throw std::runtime_error("error: JumpPad entity requires at least 2 lines");
} }
std::istringstream iss2(lines[1]); std::istringstream iss(lines[1]);
std::string targetName; std::string targetName;
// String32 target targetName // String32 target targetName
if ( ! (iss2 >> trash >> trash >> targetName) ) { if ( ! (iss >> trash >> trash >> targetName) ) {
std::cerr << "error: JumpPad entity requires target name" << std::endl; throw std::runtime_error("error: JumpPad entity requires target name");
} }
convertedLines.push_back ( "\"classname\" \"trigger_push\"\n" ); convertedLines.push_back ( "\"classname\" \"trigger_push\"\n" );
std::stringstream oss; std::stringstream oss;
oss << "\"target\" \"" << targetName << "\"" << std::endl; oss << "\"target\" \"" << targetName << "\"" << std::endl;
convertedLines.push_back ( oss.str() ); convertedLines.push_back ( oss.str() );
return convertedLines;
} }
else if ( type == "Teleporter" ) { ///TELEPORTER
std::vector<std::string>
EntityConverter::convertTeleporter(std::vector<std::string> &lines)
{
std::vector<std::string> convertedLines;
std::string trash;
if ( lines.size() < 2 ) { if ( lines.size() < 2 ) {
throw std::runtime_error("error: Teleport entity requires at least 2 lines"); throw std::runtime_error("error: Teleport entity requires at least 2 lines");
} }
std::istringstream iss2(lines[1]); std::istringstream iss(lines[1]);
std::string targetName; std::string targetName;
// String32 target targetName // String32 target targetName
if ( ! (iss2 >> trash >> trash >> targetName) ) { if ( ! (iss >> trash >> trash >> targetName) ) {
throw std::runtime_error( "error: Teleport entity requires target name" ); throw std::runtime_error( "error: Teleport entity requires target name" );
} }
@ -218,8 +287,18 @@ std::vector<std::string> EntityConverter::convert(std::vector<std::string> lines
std::stringstream oss; std::stringstream oss;
oss << "\"target\" \"" << targetName << std::endl; oss << "\"target\" \"" << targetName << std::endl;
convertedLines.push_back ( oss.str() ); convertedLines.push_back ( oss.str() );
return convertedLines;
} }
else if ( type == "Target" ) { ///TARGET
std::vector<std::string>
EntityConverter::convertTarget(std::vector<std::string> &lines)
{
std::vector<std::string> convertedLines;
std::string coords[3];
std::string trash;
if ( lines.size() < 3 ) { if ( lines.size() < 3 ) {
throw std::runtime_error("error: Target entity requires at least 3 lines"); throw std::runtime_error("error: Target entity requires at least 3 lines");
} }
@ -231,20 +310,20 @@ std::vector<std::string> EntityConverter::convert(std::vector<std::string> lines
bool haveAngle = false; bool haveAngle = false;
for (int i = 1; i < lines.size(); i++) { for (int i = 1; i < lines.size(); i++) {
type = getAttributeType(lines[i]); std::string type = getAttributeType(lines[i]);
if ( type == "position" ) { if ( type == "position" ) {
std::istringstream iss2(lines[i]); std::istringstream iss(lines[i]);
// Vector3 position coord0 coord1 coord2 // Vector3 position coord0 coord1 coord2
if ( ! (iss2 >> trash >> trash >> if ( ! (iss >> trash >> trash >>
coords[0] >> coords[1] >> coords[2])) { coords[0] >> coords[1] >> coords[2])) {
throw std::runtime_error( "error: Target entity requires coordinates" ); throw std::runtime_error( "error: Target entity requires coordinates" );
} }
havePosition = true; havePosition = true;
} }
else if ( type == "name" ) { else if ( type == "name" ) {
std::istringstream iss2(lines[i]); std::istringstream iss(lines[i]);
// UInt8 name uniqueName // UInt8 name uniqueName
if ( ! (iss2 >> trash >> trash >> targetName) ) { if ( ! (iss >> trash >> trash >> targetName) ) {
throw std::runtime_error( "error: Target entity requires target name" ); throw std::runtime_error( "error: Target entity requires target name" );
} }
haveName = true; haveName = true;
@ -284,22 +363,47 @@ std::vector<std::string> EntityConverter::convert(std::vector<std::string> lines
convertedLines.push_back (oss3.str() ); convertedLines.push_back (oss3.str() );
} }
} }
}
else if ( type == "Effect" ) { ///EFFECT
// to be implemented
}
else if ( type == "PointLight" ) { ////POINT LIGHT
// to be implemented
}
else if ( type == "Prefab" ) { ////PREFAB
// to be implemented?
}
else if ( type == "CameraPath" ) { ///CAMERA PATH
// to be implemented?
}
else if ( type == "WorldSpawn" ) { ///WORLD SPAWN
// do nothing
}
return convertedLines; return convertedLines;
} }
std::vector<std::string>
EntityConverter::convertRaceStart(std::vector<std::string> &lines)
{
std::vector<std::string> convertedLines;
return convertedLines;
}
std::vector<std::string>
EntityConverter::convertRaceFinish(std::vector<std::string> &lines)
{
std::vector<std::string> convertedLines;
return convertedLines;
}
// DEBUG
void
EntityConverter::printMapping()
{
std::map<int, std::string>::iterator it;
for (it=pickupMapping_.begin(); it!=pickupMapping_.end(); ++it)
std::cout << it->first << " => " << it->second << std::endl;
}
// DEBUG
void
EntityConverter::printTargetSources()
{
std::map<std::string, std::string>::iterator it;
for (it=targetMap_.begin(); it!=targetMap_.end(); ++it)
std::cout << it->first << " => " << it->second << std::endl;
}

View File

@ -4,6 +4,13 @@
* Filename: EntityConverter.hpp * Filename: EntityConverter.hpp
* *
* Description: Convert reflex entities to xonotic entities * Description: Convert reflex entities to xonotic entities
* - Simple; operates on single entity at a time
* - Only context provided is information on what entities are related.
* (i.e. a teleport and it's destination) Can get this information
* through the pre-scan constructor of the .map file or by providing
* a queue of all the entities in the file.
* - Throws exceptions upon encountering malformed entities and when
* IO errors occur during object instantiation
* *
* Version: 1.0 * Version: 1.0
* Created: 05/27/2017 08:21:14 AM * Created: 05/27/2017 08:21:14 AM
@ -19,6 +26,8 @@
#define ENTITY_CONVERTER_HPP #define ENTITY_CONVERTER_HPP
// Reflex Format // Reflex Format
// -****While Worldspawn is an entity, an external parser handles
// this because it contains all other entities
// -"Pickup" denoted by ID // -"Pickup" denoted by ID
// conventional item and weapon conversion stored in r2x.ent // conventional item and weapon conversion stored in r2x.ent
// -"PlayerSpawn" consists of coordinate (Vector3), // -"PlayerSpawn" consists of coordinate (Vector3),
@ -30,7 +39,9 @@
// -"Target" stored as a position (Vector3) and // -"Target" stored as a position (Vector3) and
// "name" (String32) // "name" (String32)
// ***Target can be destination of teleports OR jump pads // ***Target can be destination of teleports OR jump pads
// -MORE TO BE ADDED (Effect, liquids etc) // -"RaceStart" stored as a brush
// -"RaceFinish" stored as a brush
// -MORE TO BE ADDED? (Effect, PointLight, Prefab, CameraPath, liquids)
// Xonotic Format // Xonotic Format
// -pickups prefixed by either "item_" or "weapon_" // -pickups prefixed by either "item_" or "weapon_"
@ -55,6 +66,8 @@
// a coordinate "origin" (vector3), // a coordinate "origin" (vector3),
// an angle "angle" (a single number), // an angle "angle" (a single number),
// a target "targetname" // a target "targetname"
// -checkpoints stored as "trigger_race_checkpoint",
// a count "cnt", where "cnt" "0" is the finish line (start line?)
#include <map> #include <map>
#include <string> #include <string>
@ -63,14 +76,92 @@
class EntityConverter class EntityConverter
{ {
public: public:
/*
*--------------------------------------------------------------------------------------
* Class: EntityConverter
* Method: Constructor
* Description: Creates entity format mapping
* CAUTION: Requires matchRelated method to be called after this
* Requires: .ent filename for mapping entities from reflex format to xonotic format
* THROWS: runtime_error on .ent format error
* THROWS: std::ios::failure on IO failure
*--------------------------------------------------------------------------------------
*/
EntityConverter(std::string entityMapFile);
/*
*--------------------------------------------------------------------------------------
* Class: EntityConverter
* Method: Constructor
* Description: Creates entity format mapping and pre-scans for related entities
* Parameter: string entityMapFile, file maps source to target entity formats
* Parameter: string reflexMapFile, for pre-scan
* THROWS: runtime_error on .ent format error
* THROWS: std::ios::failure on IO failure
*--------------------------------------------------------------------------------------
*/
EntityConverter(std::string entityMapFile, std::string reflexMapFile); EntityConverter(std::string entityMapFile, std::string reflexMapFile);
/*
*--------------------------------------------------------------------------------------
* Class: EntityConverter
* Method: EntityConverter :: convert
* Description: Converts a single entity from reflex to xonotic format
* Parameter: vector of strings "lines", lines that comprise a single entity
* Return: vector of strings, single entity in the converted format
* THROWS: runtime_error on malformed .map file
* THROWS: runtime_error when called before related entitios are matched
*--------------------------------------------------------------------------------------
*/
std::vector<std::string> convert(std::vector<std::string> lines); std::vector<std::string> convert(std::vector<std::string> lines);
protected: protected:
private: private:
/*
*--------------------------------------------------------------------------------------
* Class: EntityConverter
* Method: EntityConverter :: getAttributeType
* Description: Extracts the type from a line
* Parameter: string "line", entity keyword followed by the type
*--------------------------------------------------------------------------------------
*/
std::string getAttributeType(std::string line); std::string getAttributeType(std::string line);
/*
*--------------------------------------------------------------------------------------
* Class: EntityConverter
* Method: EntityConverter :: mapEntities
* Description: Prepare pickupMapping_
* Parameter: string mapFile, filename of pickup mapping
* Return: true if no error, false if error
*--------------------------------------------------------------------------------------
*/
void mapEntities(std::string mapFile);
/*
*--------------------------------------------------------------------------------------
* Class: EntityConverter
* Method: EntityConverter :: convert~EntityName~
* Description: Multiple methods to convert entity from reflex to xonotic format
* Parameter: vector of strings entity, multi-lined entity
* Return: vector of strings, the converted entity
*--------------------------------------------------------------------------------------
*/
std::vector<std::string> convertPickup(std::vector<std::string> &entity);
std::vector<std::string> convertPlayerSpawn(std::vector<std::string> &entity);
std::vector<std::string> convertJumpPad(std::vector<std::string> &entity);
std::vector<std::string> convertTeleporter(std::vector<std::string> &entity);
std::vector<std::string> convertTarget(std::vector<std::string> &entity);
std::vector<std::string> convertRaceStart(std::vector<std::string> &entity);
std::vector<std::string> convertRaceFinish(std::vector<std::string> &entity);
void printMapping(); //DEBUG void printMapping(); //DEBUG
void printTargetSources(); //DEBUG void printTargetSources(); //DEBUG
// Related entities must be matched prior to entity conversion
bool areEntitiesMatched_;
// Map Reflex pickup IDs to Xonotic pickup identifiers // Map Reflex pickup IDs to Xonotic pickup identifiers
std::map<int, std::string> pickupMapping_; std::map<int, std::string> pickupMapping_;
// Map targets (by name) to their source type // Map targets (by name) to their source type

@ -0,0 +1 @@
Subproject commit 11faadeba77d05a80c751e97142875c4b296fa87

View File

@ -8,7 +8,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <cxxopts.hpp> #include "cxxopts.hpp"
#include "oopless-parser.hpp" #include "oopless-parser.hpp"
#include "brushdef.hpp" #include "brushdef.hpp"