From 717be4c3a868d9843675c4c222ff9e433913f796 Mon Sep 17 00:00:00 2001 From: suhrke Date: Tue, 6 Jun 2017 18:22:54 -0700 Subject: [PATCH] Added entity converter, need integration --- ReflexToQ3/Makefile | 12 +- ReflexToQ3/includes/EntityConverter.cpp | 254 ++++++++++++++++++++++++ ReflexToQ3/includes/EntityConverter.hpp | 76 +++++++ ReflexToQ3/r2x.ent | 25 +++ 4 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 ReflexToQ3/includes/EntityConverter.cpp create mode 100644 ReflexToQ3/includes/EntityConverter.hpp create mode 100644 ReflexToQ3/r2x.ent diff --git a/ReflexToQ3/Makefile b/ReflexToQ3/Makefile index 062b8b3..41047a7 100644 --- a/ReflexToQ3/Makefile +++ b/ReflexToQ3/Makefile @@ -1,14 +1,15 @@ EX=reflex2q3 CC=g++ CFLAGS=-std=c++11 -I"includes" -I"/usr/include/eigen3" +TESTEX=test/test-parser all: main test -main: planes.o brushdef.o oopless-parser.o +main: planes.o brushdef.o oopless-parser.o EntityConverter.o $(CC) $^ main.cpp $(CFLAGS) -o $(EX) 2>error8.log test: planes.o brushdef.o oopless-parser.o test-parser.o - $(CC) $^ $(CFLAGS) -o test/test-parser + $(CC) $^ $(CFLAGS) -o $(TESTEX) test-parser.o: test/test-parser.cpp $(CC) -c $^ $(CFLAGS) @@ -21,3 +22,10 @@ brushdef.o: includes/brushdef.cpp planes.o: includes/planes.cpp $(CC) -c $^ $(CFLAGS) + +EntityConverter.o: includes/EntityConverter.cpp + $(CC) -c $^ $(CFLAGS) + +clean: + rm *.o *.log $(EX) $(TESTEX) + diff --git a/ReflexToQ3/includes/EntityConverter.cpp b/ReflexToQ3/includes/EntityConverter.cpp new file mode 100644 index 0000000..4e28b22 --- /dev/null +++ b/ReflexToQ3/includes/EntityConverter.cpp @@ -0,0 +1,254 @@ +/* + * ===================================================================================== + * + * Filename: EntityConverter.cpp + * + * Description: Convert Reflex entities into Xonotic entities + * + * Version: 0.1 + * Created: 06/05/2017 07:15:25 PM + * Revision: none + * Compiler: gcc + * + * Author: suhrke@teknik.io + * + * ===================================================================================== + */ + +#include "EntityConverter.hpp" + +#include +#include +#include +#include + + + +EntityConverter::EntityConverter(std::string entityMapFile) +{ + //Open .ent mapping file + std::ifstream fin; + fin.open(entityMapFile); + + if ( ! fin.is_open() ) { + throw std::ios::failure( "Error opening .ent file" ); + } + + //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(id, pickup) ); + } +} + + +// DEBUG +void EntityConverter::printMapping() +{ + std::map::iterator it; + for (it=pickupMapping.begin(); it!=pickupMapping.end(); ++it) + std::cout << it->first << " => " << it->second << std::endl; +} + + + +std::string EntityConverter::getAttributeType(std::string line) +{ + std::string type; + std::string dataType; + std::istringstream iss(line); + if ( ! (iss >> dataType >> type )) { + return std::string(); + } + + return type; +} + + + +std::vector EntityConverter::convert(std::vector lines) +{ + std::vector convertedLines; + std::string coords[3]; + std::string attribute; + 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 ) { + std::cerr << "error: Pickup entity requires at least 3 lines" << std::endl; + return convertedLines; + } + //can ignore angle of pickups in xonotic format + int pickupID; + bool havePosition = false; + bool havePickupID = false; + + for (int i = 1; i < lines.size(); i++) { + type = getAttributeType(lines[i]); + if ( type == "position" ) { + std::istringstream iss2(lines[i]); + // Vector3 position coord0 coord1 coord2 + if ( ! (iss2 >> trash >> trash >> + coords[0] >> coords[1] >> coords[2])) { + std::cerr << "error: Pickup entity requires coordinates" << std::endl; + return convertedLines; + } + havePosition = true; + } + else if ( type == "pickupType" ) { + std::istringstream iss2(lines[i]); + // UInt8 pickupType ID + if ( ! (iss2 >> trash >> trash >> pickupID) ) { + std::cerr << "error: Pickup entity requires pickup ID" << std::endl; + return convertedLines; + } + havePickupID = true; + } + } + + if ( havePosition && havePickupID ) { + std::stringstream oss; + oss << "\"classname\" \"" << pickupMapping[pickupID] << "\"" << std::endl; + convertedLines.push_back ( oss.str() ); + // coordinates reordered to x, z, y + std::stringstream oss2; + oss2 << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << + coords[1] << "\"" << std::endl; + convertedLines.push_back ( oss2.str() ); + } + } + else if ( type == "PlayerSpawn" ) { ///PLAYER SPAWN + //minimum of 3 lines, max of ? lines + std::istringstream iss2(lines[1]); + } + else if ( type == "JumpPad" ) { ///JUMP PAD + if ( lines.size() < 2 ) { + std::cerr << "error: JumpPad entity requires at least 2 lines" << std::endl; + } + std::istringstream iss2(lines[1]); + std::string targetName; + // String32 target targetName + if ( ! (iss2 >> trash >> trash >> targetName) ) { + std::cerr << "error: JumpPad entity requires target name" << std::endl; + } + + convertedLines.push_back ( "\"classname\" \"trigger_push\"\n" ); + std::stringstream oss; + oss << "\"target\" \"" << targetName << std::endl; + convertedLines.push_back ( oss.str() ); + } + else if ( type == "Teleporter" ) { ///TELEPORTER + /* if ( lines.size() < 2 ) { + throw std::runtime_error("error: Teleport entity requires at least 2 lines"); + } + std::istringstream iss2(lines[1]); + std::string targetName; + // String32 target targetName + if ( ! (iss2 >> trash >> trash >> targetName) ) { + throw std::runtime_error( "error: Teleport entity requires target name" ); + } + + convertedLines.push_back ( "\"classname\" \"trigger_teleport\"\n" ); + std::stringstream oss; + oss << "\"target\" \"" << targetName << std::endl; + convertedLines.push_back ( oss.str() ); + } + else if ( type == "Target" ) { ///TARGET + if ( lines.size() < 3 ) { + throw std::runtime_error("error: Target entity requires at least 3 lines"); + } + //position and name required, angles optional + std::string targetName; + std::string angle; + bool havePosition = false; + bool haveName = false; + bool haveAngle = false; + + for (int i = 1; i < lines.size(); i++) { + type = getAttributeType(lines[i]); + if ( type == "position" ) { + std::istringstream iss2(lines[i]); + // Vector3 position coord0 coord1 coord2 + if ( ! (iss2 >> trash >> trash >> + coords[0] >> coords[1] >> coords[2])) { + throw std::runtime_error( "error: Target entity requires coordinates" ); + } + havePosition = true; + } + else if ( type == "name" ) { + std::istringstream iss2(lines[i]); + // UInt8 name uniqueName + if ( ! (iss2 >> trash >> trash >> targetName) ) { + throw std::runtime_error( "error: Target entity requires target name" ); + } + haveName = true; + } + else if ( type == "angles" ) { + std::istringstream iss2(lines[i]); + // Vector3 angles angle notapplicable notapplicable + if ( ! (iss2 >> trash >> trash >> angle) ) { + throw std::runtime_error( "error: Target entity requires target angle if specified" ); + } + haveAngle = true; + } + + } + + if ( havePosition && haveName) { + //**! no way to tell if teleporter or jump pad dest from targetName alone + convertedLines.push_back ( "\"classname\" \"misc_teleporter_dest\"\n" ); + std::stringstream oss; + oss << "\"targetname\" \"" << targetName << "\"\n"; + convertedLines.push_back ( oss.str() ); + // coordinates reordered to x, z, y + std::stringstream oss2; + oss2 << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << + coords[1] << "\"" << std::endl; + convertedLines.push_back ( oss2.str() ); + + // Write angle only if position and name exist + if ( haveAngle ) { + std::stringstream oss3; + oss3 << "\"angle\" \"" << angle << "\"\n"; + 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; +} diff --git a/ReflexToQ3/includes/EntityConverter.hpp b/ReflexToQ3/includes/EntityConverter.hpp new file mode 100644 index 0000000..0b9428d --- /dev/null +++ b/ReflexToQ3/includes/EntityConverter.hpp @@ -0,0 +1,76 @@ +/* + * ===================================================================================== + * + * Filename: EntityConverter.hpp + * + * Description: Convert reflex entities to xonotic entities + * + * Version: 1.0 + * Created: 05/27/2017 08:21:14 AM + * Revision: none + * Compiler: gcc + * + * Author: suhrke@teknik.io + * + * ===================================================================================== + */ + +#ifndef ENTITY_CONVERTER_HPP +#define ENTITY_CONVERTER_HPP + +// Reflex Format +// -"Pickup" denoted by ID +// conventional item and weapon conversion stored in r2x.ent +// -"PlayerSpawn" consists of coordinate (Vector3), +// angle (first element of Vector3), +// team indicator (on individual lines), +// game type indicator (on individual lines) +// -"JumpPad" stored as a brush and a Target +// -"Teleporter" stored as a brush and a Target +// -"Target" stored as a position (Vector3) and +// "name" (String32) +// ***Target can be destination of teleports OR jump pads +// -MORE TO BE ADDED (Effect, liquids etc) + +// Xonotic Format +// -pickups prefixed by either "item_" or "weapon_" +// -spawns stored as separate entity types +// "info_player_deathmatch" +// "info_player_team1" +// "info_player_team2" +// "info_player_team3" +// "info_player_team4" +// where each consists of a coordinate "origin" (vector3) +// an angle "angle" (a single number) +// -jump pads stored as "classname" "target_push", +// a coordinate "origin" (vector3), +// a target "targetname" +// OR stored as "classname" "trigger_push", +// a target "target", +// a brush +// -teleports stored as "classname" "trigger_teleport" +// a target "target", +// a brush +// -teleport destinations stored as "classname" "misc_teleporter_dest", +// a coordinate "origin" (vector3), +// an angle "angle" (a single number), +// a target "targetname" + +#include +#include +#include + +class EntityConverter +{ + public: + EntityConverter(std::string entityMapFile); + std::vector convert(std::vector lines); + void printMapping(); //DEBUG + protected: + private: + std::string getAttributeType(std::string line); + std::map pickupMapping; +}; + +#endif //ENTITY_CONVERTER_HPP + diff --git a/ReflexToQ3/r2x.ent b/ReflexToQ3/r2x.ent new file mode 100644 index 0000000..85f81ed --- /dev/null +++ b/ReflexToQ3/r2x.ent @@ -0,0 +1,25 @@ +40 item_health_small +41 item_health_medium +42 item_health_large +43 item_health_mega +50 item_armor_small +51 item_armor_medium +52 item_armor_large +53 item_armor_big +1 weapon_uzi +2 weapon_grenadelauncher +3 weapon_hagar +4 weapon_rocketlauncher +5 weapon_electro +6 weapon_nex +20 burst +21 item_shells +22 item_rockets +23 item_cells +24 item_rockets +25 item_bullets +26 item_cells +60 item_strength +62 item_invincible +70 item_flag_team1 +71 item_flag_team2