Reorganized, expanded pickup file to include other entities, now .ent
This commit is contained in:
833
src/EntityConverter.cpp
Normal file
833
src/EntityConverter.cpp
Normal file
@@ -0,0 +1,833 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: EntityConverter.cpp
|
||||
*
|
||||
* Description: Convert Reflex entities into Xonotic entities
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 06/05/2017 07:15:25 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: surkeh@protonmail.com
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "EntityConverter.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* PUBLIC
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
EntityConverter::EntityConverter(const std::string &entityMapFile) :
|
||||
OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0),
|
||||
OUTPUT_PRECISION(10)
|
||||
{
|
||||
//MUST RUN extractMapInfo method after this constructor
|
||||
haveMapInfo_ = false;
|
||||
// game modes default to enabled
|
||||
ws_.cts = true;
|
||||
ws_.ctf = true;
|
||||
ws_.ffa = true;
|
||||
ws_.tdm = true;
|
||||
ws_.duel = true;
|
||||
|
||||
mapEntities(entityMapFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
EntityConverter::EntityConverter(const std::string &entityMapFile,
|
||||
const std::string &reflexMapFile) : OFFSET_PLAYER(32.0),
|
||||
OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0), OUTPUT_PRECISION(10)
|
||||
{
|
||||
haveMapInfo_ = false;
|
||||
// game modes default to enabled
|
||||
ws_.cts = true;
|
||||
ws_.ctf = true;
|
||||
ws_.ffa = true;
|
||||
ws_.tdm = true;
|
||||
ws_.duel = true;
|
||||
|
||||
mapEntities(entityMapFile);
|
||||
|
||||
// Pre-scan for info needed by converter
|
||||
std::ifstream fin;
|
||||
fin.open(reflexMapFile);
|
||||
|
||||
if ( fin.is_open() ) {
|
||||
//Extract the source type of targets (teleporters or jump pads)
|
||||
std::string line;
|
||||
while (std::getline(fin, line)) {
|
||||
extractFromEntity(line, fin);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::ios::failure( "Error: EntityConverter failed to open .map file " + reflexMapFile );
|
||||
}
|
||||
fin.close();
|
||||
haveMapInfo_ = true;
|
||||
|
||||
//DEBUG
|
||||
//printMapping();
|
||||
//printTargetSources();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
EntityConverter::extractMapInfo(std::queue<std::vector<std::string>> entities)
|
||||
{
|
||||
if( haveMapInfo_ ) {
|
||||
std::cerr << "Map info already extracted, doing nothing" << std::endl;
|
||||
}
|
||||
else {
|
||||
while ( ! entities.empty() ) {
|
||||
std::vector<std::string> entity( entities.front() );
|
||||
entities.pop();
|
||||
|
||||
std::stringstream ss;
|
||||
std::copy(entity.begin(), entity.end(),
|
||||
std::ostream_iterator<std::string>(ss, "\n"));
|
||||
|
||||
std::string nextLine;
|
||||
if ( getline(ss, nextLine )) {
|
||||
extractFromEntity(nextLine, ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
haveMapInfo_ = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
EntityConverter::extractMapInfo(const std::vector<std::vector<std::string>> &entities)
|
||||
{
|
||||
if( haveMapInfo_ ) {
|
||||
std::cerr << "Map info already extracted, doing nothing" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::vector<std::vector<std::string>>::const_iterator it;
|
||||
for ( it=entities.begin(); it!=entities.end(); ++it ) {
|
||||
std::vector<std::string> entity( *it );
|
||||
|
||||
std::stringstream ss;
|
||||
std::copy(entity.begin(), entity.end(),
|
||||
std::ostream_iterator<std::string>(ss, "\n"));
|
||||
|
||||
std::string nextLine;
|
||||
if ( getline(ss, nextLine )) {
|
||||
extractFromEntity(nextLine, ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
haveMapInfo_ = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convert(const std::vector<std::string> &lines)
|
||||
{
|
||||
if ( haveMapInfo_ )
|
||||
{
|
||||
std::string attribute;
|
||||
std::string trash; //unused tokens
|
||||
|
||||
std::string type;
|
||||
if ( lines.size() < 1 ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: empty entity cannot be converted", lines ));
|
||||
}
|
||||
// second token is the type
|
||||
std::istringstream iss(lines[0]);
|
||||
if ( ! (iss >> trash >> type)) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: type is required", lines ));
|
||||
}
|
||||
|
||||
// If worldspawn, first reenable all gamemodes
|
||||
// then check worldspawn for disabled modes
|
||||
// then RETURN EMPTY VECTOR
|
||||
if ( type == "WorldSpawn" ) {
|
||||
ws_.cts = true;
|
||||
ws_.ctf = true;
|
||||
ws_.ffa = true;
|
||||
ws_.tdm = true;
|
||||
ws_.duel = true;
|
||||
|
||||
// Each worldspawn can specify modes enabled/disabled
|
||||
for ( int i = 1; i < lines.size(); ++i ) {
|
||||
if ( lines[i].find("modeRace 0") != std::string::npos) {
|
||||
ws_.cts = false;
|
||||
}
|
||||
else if ( lines[i].find("modeCTF 0") != std::string::npos) {
|
||||
ws_.ctf = false;
|
||||
}
|
||||
else if ( lines[i].find("modeFFA 0") != std::string::npos) {
|
||||
ws_.ffa = false;
|
||||
}
|
||||
else if ( lines[i].find("modeTDM 0") != std::string::npos) {
|
||||
ws_.tdm = false;
|
||||
}
|
||||
else if ( lines[i].find("mode1v1 0") != std::string::npos) {
|
||||
ws_.duel = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else 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 if ( type == "PointLight" ) {
|
||||
return convertPointLight(lines);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Map info must be extracted prior to conversion", lines ));
|
||||
}
|
||||
|
||||
// If unsupported entity, return empty vector
|
||||
std::vector<std::string> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* PROTECTED
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertPickup(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
//can ignore angle of pickups in xonotic format
|
||||
std::string coords[3] = {"0.0", "0.0", "0.0"};
|
||||
std::string pickupID;
|
||||
std::string trash;
|
||||
bool havePickupID = false;
|
||||
|
||||
if ( lines.size() < 2 ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Pickup entity requires minimum of two lines (type and ID)", lines ));
|
||||
}
|
||||
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
std::string type = getAttributeType(lines[i]);
|
||||
if ( type == "position" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// Vector3 position coord0 coord1 coord2
|
||||
if ( ! (iss >> trash >> trash >>
|
||||
coords[0] >> coords[1] >> coords[2])) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid Pickup position", lines ));
|
||||
}
|
||||
}
|
||||
else if ( type == "pickupType" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// UInt8 pickupType ID
|
||||
if ( ! (iss >> trash >> trash >> pickupID) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Format of Pickup ID line is invalid", lines ));
|
||||
}
|
||||
havePickupID = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( havePickupID ) {
|
||||
auto pickupIter = entityMap_.find(pickupID);
|
||||
if ( pickupIter == entityMap_.end() ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Pickup ID is invalid", lines ));
|
||||
}
|
||||
std::stringstream pickupStream;
|
||||
pickupStream << "\"classname\" \"" << pickupIter->second << "\"" << std::endl;
|
||||
convertedLines.push_back ( pickupStream.str() );
|
||||
// coordinates reordered to x, z, y
|
||||
std::stringstream positionStream;
|
||||
positionStream << "\"origin\" \"" << coords[0] << " " << coords[2] << " " <<
|
||||
offset(coords[1], OFFSET_PICKUP) << "\"" << std::endl;
|
||||
convertedLines.push_back ( positionStream.str() );
|
||||
return convertedLines;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Pickup ID was not in the entity", lines ));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------------------
|
||||
* Class: EntityConverter
|
||||
* Method: EntityConverter :: convertPlayerSpawn
|
||||
* Notes: REFLEX
|
||||
* -Optionally includes angle, team indicator, and 0 or more game
|
||||
* mode indicators (defaults to all modes enabled so this line
|
||||
* is used to disable a mode. eg Bool8 modeRace 0)
|
||||
*--------------------------------------------------------------------------------------
|
||||
*/
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertPlayerSpawn(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
// Requires position coordinate
|
||||
std::string coords[3] = {"0.0", "0.0", "0.0"};
|
||||
// Requires an angle, default to 0 degrees (floating point)
|
||||
std::string angle("0.0");
|
||||
// 1-2 for corresponding team, 0 for deathmatch spawn
|
||||
int team = 0;
|
||||
std::string trash;
|
||||
bool isModeRace = ws_.cts;
|
||||
bool isModeCtf = ws_.ctf;
|
||||
bool isModeTdm = ws_.tdm;
|
||||
bool isModeFfa = ws_.ffa;
|
||||
bool isModeDuel = ws_.duel;
|
||||
|
||||
|
||||
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
std::string type = getAttributeType(lines[i]);
|
||||
if ( type == "position" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// Vector3 position coord0 coord1 coord2
|
||||
if ( ! (iss >> trash >> trash >>
|
||||
coords[0] >> coords[1] >> coords[2])) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid PlayerSpawn position", lines ));
|
||||
}
|
||||
}
|
||||
else if ( type == "angles" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// UInt8 pickupType ID
|
||||
if ( ! (iss >> trash >> trash >> angle )) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid PlayerSpawn angle", lines ));
|
||||
}
|
||||
}
|
||||
// Bool8 modeX 0 indicates this spawn is not for game mode X
|
||||
else if ( type == "modeRace" ) {
|
||||
isModeRace = false;
|
||||
}
|
||||
else if ( type == "modeCTF" ) {
|
||||
isModeCtf = false;
|
||||
}
|
||||
else if ( type == "modeTDM" ) {
|
||||
isModeTdm = false;
|
||||
}
|
||||
else if ( type == "modeFFA" ) {
|
||||
isModeFfa = false;
|
||||
}
|
||||
else if ( type == "mode1v1" ) {
|
||||
isModeDuel = false;
|
||||
}
|
||||
else if ( type == "teamA" ) {
|
||||
team = 2; // Bool8 teamA 0 indicates teamB only
|
||||
}
|
||||
else if ( type == "teamB" ) {
|
||||
team = 1; // Bool8 teamB 0 indicates teamA only
|
||||
}
|
||||
}
|
||||
|
||||
if ( isModeCtf || isModeTdm || isModeFfa || isModeDuel ) {
|
||||
switch (team) {
|
||||
case 0:
|
||||
convertedLines.push_back ( "\"classname\" \"info_player_deathmatch\"\n" );
|
||||
break;
|
||||
case 1:
|
||||
convertedLines.push_back ( "\"classname\" \"info_player_team1\"\n" );
|
||||
break;
|
||||
case 2:
|
||||
convertedLines.push_back ( "\"classname\" \"info_player_team2\"\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
convertedLines.push_back ( "\"classname\" \"info_player_race\"\n" );
|
||||
// Reflex maps have only start and finish, point to start on spawn
|
||||
convertedLines.push_back ( "\"target\" \"cp1\"\n" );
|
||||
// Reflex maps are only cts, set spawn to cts-only type
|
||||
convertedLines.push_back ( "\"race_place\" \"-1\"\n" );
|
||||
}
|
||||
|
||||
std::stringstream positionStream;
|
||||
// coordinates reordered to x, z, y
|
||||
positionStream << "\"origin\" \"" << coords[0] << " " << coords[2] << " " <<
|
||||
offset(coords[1], OFFSET_PLAYER) << "\"" << std::endl;
|
||||
convertedLines.push_back ( positionStream.str() );
|
||||
std::stringstream angleStream;
|
||||
angleStream << "\"angle\" \"" << adjustAngleForHandedness(angle) << "\"" << std::endl;
|
||||
convertedLines.push_back (angleStream.str() );
|
||||
return convertedLines;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertJumpPad(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
std::string targetName;
|
||||
std::string trash;
|
||||
|
||||
if ( lines.size() < 2 ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: JumpPad entity requires minimum of two lines (type and target)", lines ));
|
||||
}
|
||||
std::istringstream iss(lines[1]);
|
||||
// String32 target targetName
|
||||
if ( ! (iss >> trash >> trash >> targetName) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid JumpPad target", lines ));
|
||||
}
|
||||
|
||||
convertedLines.push_back ( "\"classname\" \"trigger_push\"\n" );
|
||||
std::stringstream oss;
|
||||
oss << "\"target\" \"" << targetName << "\"" << std::endl;
|
||||
convertedLines.push_back ( oss.str() );
|
||||
return convertedLines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertTeleporter(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
std::string targetName;
|
||||
std::string trash;
|
||||
|
||||
if ( lines.size() < 2 ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Teleport entity requires minimum of two lines (type and target)", lines ));
|
||||
}
|
||||
std::istringstream iss(lines[1]);
|
||||
// String32 target targetName
|
||||
if ( ! (iss >> trash >> trash >> targetName) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid Teleport target", lines ));
|
||||
}
|
||||
|
||||
convertedLines.push_back ( "\"classname\" \"trigger_teleport\"\n" );
|
||||
std::stringstream oss;
|
||||
oss << "\"target\" \"" << targetName << "\"" << std::endl;
|
||||
convertedLines.push_back ( oss.str() );
|
||||
return convertedLines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertTarget(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
//position and name required, angles optional
|
||||
std::string coords[3] = {"0.0", "0.0", "0.0"};
|
||||
std::string targetName;
|
||||
std::string angle = "0.0";
|
||||
std::string trash;
|
||||
bool haveName = false;
|
||||
|
||||
|
||||
if ( lines.size() < 3 ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Target entity requires minimum of two lines (type and name)", lines ));
|
||||
}
|
||||
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
std::string type = getAttributeType(lines[i]);
|
||||
if ( type == "position" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// Vector3 position coord0 coord1 coord2
|
||||
if ( ! (iss >> trash >> trash >>
|
||||
coords[0] >> coords[1] >> coords[2])) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid Target position", lines ));
|
||||
}
|
||||
}
|
||||
else if ( type == "name" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// UInt8 name uniqueName
|
||||
if ( ! (iss >> trash >> trash >> targetName) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid Target \"target\"", lines ));
|
||||
}
|
||||
haveName = true;
|
||||
}
|
||||
else if ( type == "angles" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// Vector3 angles angle notapplicable notapplicable
|
||||
if ( ! (iss >> trash >> trash >> angle) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid Target angle", lines ));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( haveName) {
|
||||
auto targetIter = targetMap_.find(targetName);
|
||||
if ( targetIter == targetMap_.end() ) {
|
||||
std::cerr << makeErrorMessage("End-game camera Target is not a supported feature in id Tech games. Skipping", lines);
|
||||
|
||||
std::vector<std::string> empty;
|
||||
return empty;
|
||||
}
|
||||
if ( targetIter->second == "Teleporter") {
|
||||
convertedLines.push_back ( "\"classname\" \"misc_teleporter_dest\"\n" );
|
||||
// coordinates reordered to x, z, y
|
||||
// teleporter height is OFFSET
|
||||
std::stringstream oss;
|
||||
oss << "\"origin\" \"" << coords[0] << " " << coords[2] << " " <<
|
||||
offset(coords[1], OFFSET_PLAYER) << "\"" << std::endl;
|
||||
convertedLines.push_back ( oss.str() );
|
||||
}
|
||||
else if ( targetIter->second == "JumpPad") {
|
||||
convertedLines.push_back ( "\"classname\" \"target_position\"\n" );
|
||||
// coordinates reordered to x, z, y
|
||||
std::stringstream oss;
|
||||
oss << "\"origin\" \"" << coords[0] << " " << coords[2] << " " <<
|
||||
coords[1] << "\"" << std::endl;
|
||||
convertedLines.push_back ( oss.str() );
|
||||
}
|
||||
std::stringstream targetStream;
|
||||
targetStream << "\"targetname\" \"" << targetName << "\"" << std::endl;
|
||||
convertedLines.push_back ( targetStream.str() );
|
||||
|
||||
// write angle every time
|
||||
std::stringstream angleStream;
|
||||
angleStream << "\"angle\" \"" << adjustAngleForHandedness(angle) << "\"" << std::endl;
|
||||
convertedLines.push_back( angleStream.str() );
|
||||
return convertedLines;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: \"target\" was not found in this Target entity", lines ));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertRaceStart(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
convertedLines.push_back ("\"classname\" \"trigger_race_checkpoint\"\n");
|
||||
convertedLines.push_back ("\"targetname\" \"cp1\"\n");
|
||||
convertedLines.push_back ("\"cnt\" \"1\"\n");
|
||||
return convertedLines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertRaceFinish(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
convertedLines.push_back ("\"classname\" \"trigger_race_checkpoint\"\n");
|
||||
convertedLines.push_back ("\"targetname\" \"finish\"\n");
|
||||
convertedLines.push_back ("\"cnt\" \"0\"\n");
|
||||
return convertedLines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
EntityConverter::convertPointLight(const std::vector<std::string> &lines) const
|
||||
{
|
||||
std::vector<std::string> convertedLines;
|
||||
//position and intensity required, color optional
|
||||
std::string coords[3] = {"0.0", "0.0", "0.0"};
|
||||
//default to a typical value
|
||||
std::string intensity = "1.0";
|
||||
//color is hex 8 digits
|
||||
//default to white if no color specified
|
||||
std::string color = "ff000000";
|
||||
std::string trash;
|
||||
bool haveColor = false;
|
||||
|
||||
|
||||
if ( lines.size() < 2 ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: PointLight entity requires at least one line (type)", lines ));
|
||||
}
|
||||
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
std::string type = getAttributeType(lines[i]);
|
||||
if ( type == "position" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// Vector3 position coord0 coord1 coord2
|
||||
if ( ! (iss >> trash >> trash >>
|
||||
coords[0] >> coords[1] >> coords[2])) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid PointLight position", lines ));
|
||||
}
|
||||
}
|
||||
else if ( type == "intensity" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// Float intensity validFloat
|
||||
if ( ! (iss >> trash >> trash >> intensity) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid PointLight intensity", lines ));
|
||||
}
|
||||
}
|
||||
else if ( type == "color" ) {
|
||||
std::istringstream iss(lines[i]);
|
||||
// ColourXRGB32 color eightDigitHexValue
|
||||
if ( ! (iss >> trash >> trash >> color) ) {
|
||||
throw std::runtime_error(
|
||||
makeErrorMessage( "error: Invalid PointLight color", lines ));
|
||||
}
|
||||
haveColor = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
convertedLines.push_back ( "\"classname\" \"light\"\n" );
|
||||
// coordinates reordered to x, z, y
|
||||
std::stringstream positionStream;
|
||||
positionStream << "\"origin\" \"" << coords[0] << " " << coords[2] << " " <<
|
||||
coords[1] << "\"" << std::endl;
|
||||
convertedLines.push_back ( positionStream.str() );
|
||||
// convert intensity
|
||||
std::stringstream intensityStream;
|
||||
intensityStream << "\"light\" \"" << adjustBrightness(intensity) << "\"\n";
|
||||
convertedLines.push_back ( intensityStream.str() );
|
||||
|
||||
float red;
|
||||
float green;
|
||||
float blue;
|
||||
// Convert 32bit hex RGBA value (ALPHA ALWAYS FULL) into RGB values
|
||||
hexToRGB(color, red, green, blue);
|
||||
|
||||
std::stringstream colorStream;
|
||||
colorStream << "\"_color\" \"" << red << " " << green << " " << blue << "\"" << std::endl;
|
||||
convertedLines.push_back (colorStream.str() );
|
||||
|
||||
return convertedLines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
EntityConverter::getAttributeType(const std::string &line) const
|
||||
{
|
||||
std::string type;
|
||||
std::string dataType;
|
||||
std::istringstream iss(line);
|
||||
if ( ! (iss >> dataType >> type )) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
EntityConverter::mapEntities(const 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
|
||||
std::string id;
|
||||
std::string pickup;
|
||||
if ( ! (iss >> id >> pickup)) {
|
||||
throw std::runtime_error( "format error in Pickup .pck file " + mapFile );
|
||||
}
|
||||
entityMap_.insert ( std::pair<std::string, std::string>(id, pickup) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::ios::failure( "Error: EntityConverter failed to open .ent file" );
|
||||
}
|
||||
fin.close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
EntityConverter::extractFromEntity(const std::string &line, std::istream &is)
|
||||
{
|
||||
std::string trash;
|
||||
std::string targetName;
|
||||
std::string nextLine;
|
||||
if ( line.find("type Teleporter") != std::string::npos) {
|
||||
std::getline(is, nextLine);
|
||||
std::istringstream iss(nextLine);
|
||||
if ( ! (iss >> trash >> trash >> targetName)) {
|
||||
throw std::runtime_error( "Format error in .map file" );
|
||||
}
|
||||
targetMap_.insert ( std::pair<std::string, std::string>(targetName, "Teleporter") );
|
||||
}
|
||||
else if ( line.find("type JumpPad") != std::string::npos) {
|
||||
std::getline(is, nextLine);
|
||||
std::istringstream iss(nextLine);
|
||||
if ( ! (iss >> trash >> trash >> targetName)) {
|
||||
throw std::runtime_error( "Format error in .map file" );
|
||||
}
|
||||
targetMap_.insert ( std::pair<std::string, std::string>(targetName, "JumpPad") );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
EntityConverter::offset(const std::string &value, const float amount) const
|
||||
{
|
||||
std::istringstream iss(value);
|
||||
float c;
|
||||
iss >> c;
|
||||
c += amount;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::fixed << std::setprecision(OUTPUT_PRECISION) << c;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
EntityConverter::adjustAngleForHandedness(const std::string &angle) const
|
||||
{
|
||||
std::istringstream iss(angle);
|
||||
float a;
|
||||
iss >> a;
|
||||
a = -a + 90.0;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::fixed << std::setprecision(OUTPUT_PRECISION) << a;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
EntityConverter::hexToRGB(const std::string &hex, float &r, float &g, float &b) const
|
||||
{
|
||||
unsigned int value;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << hex;
|
||||
ss >> value;
|
||||
|
||||
// BYTE ORDER IS ARGB
|
||||
// Alpha value is always full -> can be ignored safely
|
||||
// Get each value and normalize
|
||||
r = ((value >> 16) & 0xFF) / 255.0;
|
||||
g = ((value >> 8) & 0xFF) / 255.0;
|
||||
b = ((value) & 0xFF) / 255.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
EntityConverter::adjustBrightness(const std::string &value) const
|
||||
{
|
||||
float inputBright;
|
||||
std::stringstream ss(value);
|
||||
ss >> inputBright;
|
||||
|
||||
return static_cast<int>(inputBright * BRIGHTNESS_ADJUST);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
EntityConverter::makeErrorMessage(const std::string message,
|
||||
const std::vector<std::string> entity) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::endl << message << ":" << std::endl;
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for ( it=entity.begin(); it!=entity.end(); ++it ) {
|
||||
ss << *it << std::endl;
|
||||
}
|
||||
|
||||
ss << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* PRIVATE
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
// DEBUG
|
||||
void
|
||||
EntityConverter::printMapping() const
|
||||
{
|
||||
std::cout << std::endl << "Reflex pickup ID mapped to Xonotic pickup names: " << std::endl;
|
||||
std::map<std::string, std::string>::const_iterator it;
|
||||
for ( it=entityMap_.begin(); it!=entityMap_.end(); ++it )
|
||||
std::cout << it->first << " => " << it->second << std::endl;
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
void
|
||||
EntityConverter::printTargetSources() const
|
||||
{
|
||||
std::cout << std::endl << "Target and Sources: " << std::endl;
|
||||
std::map<std::string, std::string>::const_iterator it;
|
||||
for ( it=targetMap_.begin(); it!=targetMap_.end(); ++it )
|
||||
std::cout << it->first << " => " << it->second << std::endl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user