Added entity converter, need integration

This commit is contained in:
suhrke 2017-06-06 18:22:54 -07:00
parent df350ac0d0
commit 717be4c3a8
4 changed files with 365 additions and 2 deletions

View File

@ -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)

View File

@ -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 <exception>
#include <fstream>
#include <iostream>
#include <sstream>
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<int, std::string>(id, pickup) );
}
}
// 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;
}
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<std::string> EntityConverter::convert(std::vector<std::string> lines)
{
std::vector<std::string> 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;
}

View File

@ -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 <map>
#include <string>
#include <vector>
class EntityConverter
{
public:
EntityConverter(std::string entityMapFile);
std::vector<std::string> convert(std::vector<std::string> lines);
void printMapping(); //DEBUG
protected:
private:
std::string getAttributeType(std::string line);
std::map<int, std::string> pickupMapping;
};
#endif //ENTITY_CONVERTER_HPP

25
ReflexToQ3/r2x.ent Normal file
View File

@ -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