Moved Recorder code from LibCarla to Unreal

This commit is contained in:
bernatx 2019-02-15 13:06:32 +01:00
parent 483b1c1f66
commit 12dd144400
38 changed files with 2202 additions and 1978 deletions

View File

@ -20,9 +20,6 @@ install(FILES ${libcarla_carla_headers} DESTINATION include/carla)
file(GLOB libcarla_carla_geom_headers "${libcarla_source_path}/carla/geom/*.h")
install(FILES ${libcarla_carla_geom_headers} DESTINATION include/carla/geom)
file(GLOB libcarla_carla_recorder_headers "${libcarla_source_path}/carla/recorder/*.h")
install(FILES ${libcarla_carla_recorder_headers} DESTINATION include/carla/recorder)
file(GLOB libcarla_carla_profiler_headers "${libcarla_source_path}/carla/profiler/*.h")
install(FILES ${libcarla_carla_profiler_headers} DESTINATION include/carla/profiler)
@ -92,8 +89,6 @@ file(GLOB libcarla_server_sources
"${libcarla_source_path}/carla/opendrive/parser/*.h"
"${libcarla_source_path}/carla/opendrive/parser/pugixml/*.cpp"
"${libcarla_source_path}/carla/opendrive/parser/pugixml/*.hpp"
"${libcarla_source_path}/carla/recorder/*.cpp"
"${libcarla_source_path}/carla/recorder/*.h"
"${libcarla_source_path}/carla/road/*.cpp"
"${libcarla_source_path}/carla/road/*.h"
"${libcarla_source_path}/carla/road/element/*.cpp"

View File

@ -1,107 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Recorder.h"
#include <ctime>
#include <sstream>
namespace carla {
namespace recorder {
Recorder::Recorder(){
}
Recorder::~Recorder(){
}
std::string Recorder::start(std::string path, std::string name, std::string mapName) {
// reset
stop();
std::stringstream filename;
filename << path << name;
// files
// file.open(filename.str(), std::ios::binary | std::ios::trunc | std::ios::out);
file.open(filename.str(), std::ios::binary);
if (!file.is_open()) {
log_error("Recorder file couldn't be created");
return "";
}
// log
log.open(filename.str() + ".log");
std::string magic("CARLA_RECORDER");
// save info
info.version = 1;
info.magic.copy_from(magic);
info.date = std::time(0);
info.mapfile.copy_from(mapName);
// write general info
info.write(file);
frames.reset();
enabled = true;
return filename.str();
}
void Recorder::stop() {
enabled = false;
if (file.is_open()) file.close();
if (log.is_open()) log.close();
// log << "Stop\n";
clear();
}
void Recorder::clear(void) {
events.clear();
positions.clear();
states.clear();
// log << "Clear\n";
}
void Recorder::write(void) {
// update this frame data
// log << "Write\n";
frames.setFrame();
frames.write(file, log);
events.write(file, log);
positions.write(file, log);
states.write(file, log);
clear();
}
void Recorder::addPosition(const RecorderPosition position) {
if (enabled)
positions.addPosition(std::move(position));
}
void Recorder::addEvent(RecorderEventAdd event) {
if (enabled)
events.addEvent(std::move(event));
}
void Recorder::addEvent(const RecorderEventDel event) {
if (enabled)
events.addEvent(std::move(event));
}
void Recorder::addEvent(const RecorderEventParent event) {
if (enabled)
events.addEvent(std::move(event));
}
void Recorder::addState(const RecorderStateTrafficLight state) {
if (enabled)
states.addState(std::move(state));
}
}
}

View File

@ -1,80 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include "carla/NonCopyable.h"
#include "carla/recorder/RecorderInfo.h"
#include "carla/recorder/RecorderFrames.h"
#include "carla/recorder/RecorderEvent.h"
#include "carla/recorder/RecorderPosition.h"
#include "carla/recorder/RecorderState.h"
#include "carla/recorder/RecorderHelpers.h"
#include "carla/recorder/Replayer.h"
namespace carla {
namespace recorder {
enum class RecorderPacketId : char {
Frame = 0,
Event,
Position,
State
};
class Recorder : private NonCopyable {
bool enabled; // enabled or not
// files
std::ofstream file;
std::ofstream log;
// structures
RecorderInfo info;
RecorderFrames frames;
RecorderEvents events;
RecorderPositions positions;
RecorderStates states;
// replayer
Replayer replayer;
public:
Recorder();
~Recorder();
void enable(void);
void disable(void);
bool isEnabled(void) { return enabled; };
std::string start(std::string path, std::string name, std::string mapName);
void stop(void);
void clear(void);
void addEvent(RecorderEventAdd event);
void addEvent(const RecorderEventDel event);
void addEvent(const RecorderEventParent event);
void addPosition(const RecorderPosition position);
void addState(const RecorderStateTrafficLight state);
void write(void);
// replayer
Replayer &getReplayer(void) {
return replayer;
}
std::string showFileInfo(std::string path, std::string name) {
return replayer.getInfo(path + name);
}
std::string replayFile(std::string path, std::string name, double timeStart, double duration) {
stop();
return replayer.replayFile(path + name, timeStart, duration);
}
};
}
}

View File

@ -1,171 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Recorder.h"
#include "RecorderEvent.h"
#include "RecorderHelpers.h"
#include "carla/rpc/ActorId.h"
#include "carla/rpc/ActorAttribute.h"
namespace carla {
namespace recorder {
void RecorderEventAdd::write(std::ofstream &file) {
//log << "add event: " << this->description.id.c_str() << " (id." << this->databaseId << ")\n";
// database id
writeValue<uint32_t>(file, this->databaseId);
// transform
writeTransform(file, this->transform);
// description type
writeValue<carla::rpc::actor_id_type>(file, this->description.uid);
writeBuffer(file, this->description.id);
// attributes
uint16_t total = this->description.attributes.size();
writeValue<uint16_t>(file, total);
//log << "Attributes: " << this->description.attributes.size() << std::endl;
for (uint16_t i=0; i<total; ++i) {
// type
writeValue<carla::rpc::ActorAttributeType>(file, this->description.attributes[i].type);
writeBuffer(file, this->description.attributes[i].id);
writeBuffer(file, this->description.attributes[i].value);
// log
//log << " " << att.id.c_str() << " = " << att.value.c_str() << std::endl;
}
}
void RecorderEventAdd::read(std::ifstream &file) {
//log << "add event: " << this->description.id.c_str() << " (id." << this->databaseId << ")\n";
// database id
readValue<uint32_t>(file, this->databaseId);
// transform
readTransform(file, this->transform);
// description type
readValue<carla::rpc::actor_id_type>(file, this->description.uid);
// text id
readBuffer(file, this->description.id);
// attributes
uint16_t total;
readValue<uint16_t>(file, total);
this->description.attributes.clear();
this->description.attributes.reserve(total);
//log << "Attributes: " << this->description.attributes.size() << std::endl;
for (uint16_t i=0; i<total; ++i) {
RecorderActorAttribute att;
// type
readValue<carla::rpc::ActorAttributeType>(file, att.type);
readBuffer(file, att.id);
readBuffer(file, att.value);
this->description.attributes.push_back(std::move(att));
// log
//log << " " << att.id.c_str() << " = " << att.value.c_str() << std::endl;
}
}
void RecorderEventDel::read(std::ifstream &file) {
// database id
readValue<uint32_t>(file, this->databaseId);
}
void RecorderEventDel::write(std::ofstream &file) {
// database id
writeValue<uint32_t>(file, this->databaseId);
}
void RecorderEventParent::read(std::ifstream &file) {
// database id
readValue<uint32_t>(file, this->databaseId);
// database id parent
readValue<uint32_t>(file, this->databaseIdParent);
}
void RecorderEventParent::write(std::ofstream &file) {
// database id
writeValue<uint32_t>(file, this->databaseId);
// database id parent
writeValue<uint32_t>(file, this->databaseIdParent);
}
//---------------------------------------------
void RecorderEvents::clear(void) {
eventsAdd.clear();
eventsDel.clear();
eventsParent.clear();
}
void RecorderEvents::addEvent(RecorderEventAdd event) {
eventsAdd.push_back(std::move(event));
}
void RecorderEvents::addEvent(const RecorderEventDel event) {
eventsDel.push_back(std::move(event));
}
void RecorderEvents::addEvent(const RecorderEventParent event) {
eventsParent.push_back(std::move(event));
}
void RecorderEvents::writeEventsAdd(std::ofstream &file) {
// write total records
uint16_t total = eventsAdd.size();
writeValue<uint16_t>(file, total);
for (unsigned long i=0; i<eventsAdd.size(); ++i) {
eventsAdd[i].write(file);
}
}
void RecorderEvents::writeEventsDel(std::ofstream &file, std::ofstream &log) {
// write total records
uint16_t total = eventsDel.size();
writeValue<uint16_t>(file, total);
for (auto rec : eventsDel) {
log << "add del: " << rec.databaseId << "\n";
rec.write(file);
}
}
void RecorderEvents::writeEventsParent(std::ofstream &file, std::ofstream &log) {
// write total records
uint16_t total = eventsParent.size();
writeValue<uint16_t>(file, total);
for (auto rec : eventsParent) {
log << "add parent: id." << rec.databaseId << ", parent." << rec.databaseIdParent << "\n";
rec.write(file);
}
}
void RecorderEvents::write(std::ofstream &file, std::ofstream &log) {
// write the packet id
writeValue<char>(file, static_cast<char>(RecorderPacketId::Event));
std::streampos posStart = file.tellp();
// write a dummy packet size
uint32_t total = 0;
writeValue<uint32_t>(file, total);
// write events
writeEventsAdd(file);
writeEventsDel(file, log);
writeEventsParent(file, log);
// write the real packet size
std::streampos posEnd = file.tellp();
total = posEnd - posStart - sizeof(uint32_t);
file.seekp(posStart, std::ios::beg);
writeValue<uint32_t>(file, total);
file.seekp(posEnd, std::ios::beg);
log << "write events (" << eventsAdd.size() << "," << eventsDel.size() << "," << eventsParent.size() << ")\n";
}
}
}

View File

@ -1,74 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/rpc/ActorDescription.h"
#include "carla/rpc/ActorAttributeType.h"
#include "carla/geom/Transform.h"
#include <fstream>
namespace carla {
namespace recorder {
struct RecorderActorAttribute {
carla::rpc::ActorAttributeType type = carla::rpc::ActorAttributeType::Int;
Buffer id; // string
Buffer value; // string
};
struct RecorderActorDescription {
carla::rpc::actor_id_type uid = 0u;
Buffer id; // string
std::vector<RecorderActorAttribute> attributes;
};
struct RecorderEventAdd {
uint32_t databaseId;
carla::geom::Transform transform;
RecorderActorDescription description;
void read(std::ifstream &file);
void write(std::ofstream &file);
};
struct RecorderEventDel {
uint32_t databaseId;
void read(std::ifstream &file);
void write(std::ofstream &file);
};
struct RecorderEventParent {
uint32_t databaseId;
uint32_t databaseIdParent;
void read(std::ifstream &file);
void write(std::ofstream &file);
};
class RecorderEvents {
public:
RecorderEvents() = default;
void addEvent(RecorderEventAdd event);
void addEvent(const RecorderEventDel event);
void addEvent(const RecorderEventParent event);
void clear(void);
void write(std::ofstream &_file, std::ofstream &log);
private:
std::vector<RecorderEventAdd> eventsAdd;
std::vector<RecorderEventDel> eventsDel;
std::vector<RecorderEventParent> eventsParent;
void writeEventsAdd(std::ofstream &file);
void writeEventsDel(std::ofstream &file, std::ofstream &log);
void writeEventsParent(std::ofstream &file, std::ofstream &log);
};
}
}

View File

@ -1,91 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Recorder.h"
#include "RecorderFrames.h"
#include "RecorderHelpers.h"
namespace carla {
namespace recorder {
void RecorderFrame::read(std::ifstream &file) {
//readValue<uint64_t>(file, this.id);
//readValue<double>(file, this.durationThis);
//readValue<double>(file, this.elapsed);
readValue<RecorderFrame>(file, *this);
}
void RecorderFrame::write(std::ofstream &file) {
//writeValue<uint64_t>(file, frame.id);
//writeValue<double>(file, frame.durationThis);
//writeValue<double>(file, frame.elapsed);
writeValue<RecorderFrame>(file, *this);
}
//---------------------------------------------
RecorderFrames::RecorderFrames(void) {
reset();
}
void RecorderFrames::reset(void) {
frame.id = 0;
frame.durationThis = 0.0f;
frame.elapsed = 0.0f;
lastTime = std::chrono::high_resolution_clock::now();
offsetPreviousFrame = 0;
}
void RecorderFrames::setFrame(void) {
auto now = std::chrono::high_resolution_clock::now();
if (frame.id == 0) {
frame.elapsed = 0.0f;
frame.durationThis = 0.0f;
}
else
{
frame.durationThis = std::chrono::duration<double>(now - lastTime).count();
frame.elapsed += frame.durationThis;
}
lastTime = now;
++frame.id;
}
void RecorderFrames::write(std::ofstream &file, std::ofstream &log) {
std::streampos pos, offset;
double dummy = -1.0f;
// write the packet id
writeValue<char>(file, static_cast<char>(RecorderPacketId::Frame));
// write the packet size
uint32_t total = sizeof(RecorderFrame);
writeValue<uint32_t>(file, total);
// write frame record
writeValue<uint64_t>(file, frame.id);
offset = file.tellp();
writeValue<double>(file, dummy);
writeValue<double>(file, frame.elapsed);
// we need to write this duration to previous frame
if (offsetPreviousFrame > 0) {
pos = file.tellp();
file.seekp(offsetPreviousFrame, std::ios::beg);
writeValue<double>(file, frame.durationThis);
file.seekp(pos, std::ios::beg);
}
// save position for next actualization
offsetPreviousFrame = offset;
log << "frame " << frame.id << " elapsed " << frame.elapsed << "\n";
}
}
}

View File

@ -1,42 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include <chrono>
namespace carla {
namespace recorder {
#pragma pack(push, 1)
struct RecorderFrame {
uint64_t id;
double durationThis;
double elapsed;
void read(std::ifstream &file);
void write(std::ofstream &file);
};
#pragma pack(pop)
class RecorderFrames {
public:
RecorderFrames(void);
void reset();
void setFrame(void);
void write(std::ofstream &file, std::ofstream &log);
private:
RecorderFrame frame;
std::streampos offsetPreviousFrame;
std::chrono::time_point<std::chrono::high_resolution_clock> lastTime;
};
}
}

View File

@ -1,107 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "RecorderHelpers.h"
namespace carla {
namespace recorder {
// write binary data from Vector3D
void writeVector3D(std::ofstream &file, const carla::geom::Vector3D &obj) {
//file.write(reinterpret_cast<const char*>(&obj.x), sizeof(float));
//file.write(reinterpret_cast<const char*>(&obj.y), sizeof(float));
//file.write(reinterpret_cast<const char*>(&obj.z), sizeof(float));
writeValue<float>(file, obj.x);
writeValue<float>(file, obj.y);
writeValue<float>(file, obj.z);
}
// write binary data from Location
void writeLocation(std::ofstream &file, const carla::geom::Location &obj) {
//file.write(reinterpret_cast<const char*>(&obj.x), sizeof(float));
//file.write(reinterpret_cast<const char*>(&obj.y), sizeof(float));
//file.write(reinterpret_cast<const char*>(&obj.z), sizeof(float));
writeValue<float>(file, obj.x);
writeValue<float>(file, obj.y);
writeValue<float>(file, obj.z);
}
// write binary data from Rotation
void writeRotation(std::ofstream &file, const carla::geom::Rotation &obj) {
writeValue<float>(file, obj.pitch);
writeValue<float>(file, obj.yaw);
writeValue<float>(file, obj.roll);
}
// write binary data from Transform
void writeTransform(std::ofstream &file, const carla::geom::Transform &obj){
writeLocation(file, obj.location);
writeRotation(file, obj.rotation);
}
// write binary data from string (length + text)
void writeString(std::ofstream &file, const std::string &obj) {
uint16_t length = obj.size();
writeValue<uint16_t>(file, length);
file.write(reinterpret_cast<const char*>(obj.c_str()), length);
}
// write binary data from buffer (length + data)
void writeBuffer(std::ofstream &file, const Buffer &obj) {
uint16_t length = obj.size();
writeValue<uint16_t>(file, length);
file.write(reinterpret_cast<const char*>(obj.data()), length);
}
// read binary data from Vector3D
void readVector3D(std::ifstream &file, carla::geom::Vector3D &obj) {
readValue<float>(file, obj.x);
readValue<float>(file, obj.y);
readValue<float>(file, obj.z);
}
// read binary data from Location
void readLocation(std::ifstream &file, carla::geom::Location &obj) {
readValue<float>(file, obj.x);
readValue<float>(file, obj.y);
readValue<float>(file, obj.z);
}
// read binary data from Rotation
void readRotation(std::ifstream &file, carla::geom::Rotation &obj) {
readValue<float>(file, obj.pitch);
readValue<float>(file, obj.yaw);
readValue<float>(file, obj.roll);
}
// read binary data from Transform
void readTransform(std::ifstream &file, carla::geom::Transform &obj){
readLocation(file, obj.location);
readRotation(file, obj.rotation);
}
// read binary data from string (length + text)
void readString(std::ifstream &file, std::string &obj) {
uint16_t length;
readValue<uint16_t>(file, length);
if (length > 0) {
obj.resize(length);
file.read(&obj[0], length);
}
}
// read binary data to buffer (length + data)
void readBuffer(std::ifstream &file, Buffer &obj) {
uint16_t length;
readValue<uint16_t>(file, length);
if (length > 0) {
obj.reset(static_cast<unsigned int>(length));
file.read(reinterpret_cast<char *>(obj.data()), length);
}
}
}
}

View File

@ -1,68 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include "carla/Buffer.h"
#include "carla/geom/Vector3D.h"
#include "carla/geom/Location.h"
#include "carla/geom/Transform.h"
#include "carla/geom/Rotation.h"
namespace carla {
namespace recorder {
//---------
// recorder
//---------
// write binary data (using sizeof())
template<typename T>
void writeValue(std::ofstream &file, const T &obj) {
file.write(reinterpret_cast<const char*>(&obj), sizeof(T));
}
// write binary data from Vector3D
void writeVector3D(std::ofstream &file, const carla::geom::Vector3D &obj);
// write binary data from Location
void writeLocation(std::ofstream &file, const carla::geom::Location &obj);
// write binary data from Transform
void writeTransform(std::ofstream &file, const carla::geom::Transform &obj);
// write binary data from Rotation
void writeRotation(std::ofstream &file, const carla::geom::Rotation &obj);
// write binary data from string (length + text)
void writeString(std::ofstream &file, const std::string &obj);
// write binary data from buffer (length + data)
void writeBuffer(std::ofstream &file, const Buffer &obj);
//---------
// replayer
//---------
// read binary data (using sizeof())
template<typename T>
void readValue(std::ifstream &file, T &obj) {
file.read(reinterpret_cast<char *>(&obj), sizeof(T));
}
// read binary data from Vector3D
void readVector3D(std::ifstream &file, carla::geom::Vector3D &obj);
// read binary data from Location
void readLocation(std::ifstream &file, carla::geom::Location &obj);
// read binary data from Transform
void readTransform(std::ifstream &file, carla::geom::Transform &obj);
// read binary data from Rotation
void readRotation(std::ifstream &file, carla::geom::Rotation &obj);
// read binary data from string (length + text)
void readString(std::ifstream &file, std::string &obj);
// read binary data to buffer (length + data)
void readBuffer(std::ifstream &file, Buffer &obj);
}
}

View File

@ -1,40 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Buffer.h"
#include "RecorderHelpers.h"
#include <fstream>
#include <ctime>
namespace carla {
namespace recorder {
struct RecorderInfo {
uint16_t version;
Buffer magic;
std::time_t date;
Buffer mapfile;
void read(std::ifstream &file) {
readValue<uint16_t>(file, version);
readBuffer(file, magic);
readValue<std::time_t>(file, date);
readBuffer(file, mapfile);
}
void write(std::ofstream &file) {
writeValue<uint16_t>(file, version);
writeBuffer(file, magic);
writeValue<std::time_t>(file, date);
writeBuffer(file, mapfile);
}
};
}
}

View File

@ -1,76 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Recorder.h"
#include "RecorderPosition.h"
#include "RecorderHelpers.h"
namespace carla {
namespace recorder {
void RecorderPosition::write(std::ofstream &file) {
// database id
writeValue<uint32_t>(file, this->databaseId);
// transform
writeTransform(file, this->transform);
// velocity
// writeVector3D(file, this->velocity);
// velocity
// writeVector3D(file, this->angularVelocity);
}
void RecorderPosition::read(std::ifstream &file) {
// database id
readValue<uint32_t>(file, this->databaseId);
// transform
readTransform(file, this->transform);
// velocity
// readVector3D(file, this->velocity);
// velocity
// readVector3D(file, this->angularVelocity);
}
//---------------------------------------------
void RecorderPositions::clear(void) {
positions.clear();
}
void RecorderPositions::addPosition(const RecorderPosition &position) {
positions.push_back(std::move(position));
//log << "add position (" << sizeof(position) << ") " << position.transform.location.x << "," << position.transform.location.y << "," << position.transform.location.z << std::endl;
//log << "add position for id." << position.id << std::endl;
}
void RecorderPositions::write(std::ofstream &file, std::ofstream &log) {
// write the packet id
writeValue<char>(file, static_cast<char>(RecorderPacketId::Position));
// write the packet size
uint32_t total = 2 + positions.size() * sizeof(RecorderPosition);
writeValue<uint32_t>(file, total);
// write total records
total = positions.size();
writeValue<short>(file, total);
// write records
file.write(reinterpret_cast<const char*>(positions.data()), positions.size() * sizeof(RecorderPosition));
/*
// write records
for (auto rec : positions) {
writeValue<uint32_t>(file, rec.id); // actor id
writeTransform(file, rec.transform); // transform
writeVector3D(file, rec.velocity); // velocity
writeVector3D(file, rec.angularVelocity); // angular velocity
}
*/
log << "write positions (" << positions.size() << " * " << sizeof(RecorderPosition) << ")\n";
}
}
}

View File

@ -1,41 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/geom/Vector3D.h"
#include "carla/geom/Transform.h"
#include <fstream>
namespace carla {
namespace recorder {
#pragma pack(push, 1)
struct RecorderPosition {
uint32_t databaseId;
carla::geom::Transform transform;
// carla::geom::Vector3D velocity;
// carla::geom::Vector3D angularVelocity;
void read(std::ifstream &file);
void write(std::ofstream &file);
};
#pragma pack(pop)
class RecorderPositions {
public:
RecorderPositions() = default;
void addPosition(const RecorderPosition &_pos);
void clear(void);
void write(std::ofstream &file,std::ofstream &log);
private:
std::vector<RecorderPosition> positions;
};
}
}

View File

@ -1,73 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Recorder.h"
#include "RecorderState.h"
#include "RecorderHelpers.h"
namespace carla {
namespace recorder {
void RecorderStateTrafficLight::write(std::ofstream &file) {
writeValue<uint32_t>(file, this->databaseId);
writeValue<bool>(file, this->isFrozen);
writeValue<float>(file, this->elapsedTime);
writeValue<char>(file, this->state);
}
void RecorderStateTrafficLight::read(std::ifstream &file) {
readValue<uint32_t>(file, this->databaseId);
readValue<bool>(file, this->isFrozen);
readValue<float>(file, this->elapsedTime);
readValue<char>(file, this->state);
}
//---------------------------------------------
void RecorderStates::clear(void) {
statesTrafficLights.clear();
}
void RecorderStates::addState(RecorderStateTrafficLight state) {
statesTrafficLights.push_back(std::move(state));
}
void RecorderStates::writeStatesTrafficLight(std::ofstream &file) {
// write total records
short total = statesTrafficLights.size();
writeValue<short>(file, total);
for (unsigned long i=0; i<statesTrafficLights.size(); ++i) {
statesTrafficLights[i].write(file);
}
}
void RecorderStates::write(std::ofstream &file, std::ofstream &log) {
// write the packet id
writeValue<char>(file, static_cast<char>(RecorderPacketId::State));
std::streampos posStart = file.tellp();
// write a dummy packet size
int total = 0;
writeValue<int>(file, total);
// write events
writeStatesTrafficLight(file);
// write the real packet size
std::streampos posEnd = file.tellp();
total = posEnd - posStart - sizeof(int);
file.seekp(posStart, std::ios::beg);
writeValue<int>(file, total);
file.seekp(posEnd, std::ios::beg);
log << "write states (" << statesTrafficLights.size() << ")\n";
}
}
}

View File

@ -1,44 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/geom/Transform.h"
#include <fstream>
namespace carla {
namespace recorder {
#pragma pack(push, 1)
struct RecorderStateTrafficLight {
uint32_t databaseId;
bool isFrozen;
float elapsedTime;
char state;
void read(std::ifstream &file);
void write(std::ofstream &file);
};
#pragma pack(pop)
class RecorderStates {
public:
RecorderStates() = default;
void addState(const RecorderStateTrafficLight state);
void clear(void);
void write(std::ofstream &_file, std::ofstream &log);
private:
std::vector<RecorderStateTrafficLight> statesTrafficLights;
void writeStatesTrafficLight(std::ofstream &file);
};
}
}

View File

@ -1,581 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Replayer.h"
#include "Recorder.h"
#include "carla/Logging.h"
#include <ctime>
#include <sstream>
namespace carla {
namespace recorder {
Replayer::Replayer() {
}
Replayer::~Replayer() {
stop();
}
// callbacks
void Replayer::setCallbackEventAdd(RecorderCallbackEventAdd f) {
callbackEventAdd = std::move(f);
}
void Replayer::setCallbackEventDel(RecorderCallbackEventDel f) {
callbackEventDel = std::move(f);
}
void Replayer::setCallbackEventParent(RecorderCallbackEventParent f) {
callbackEventParent = std::move(f);
}
void Replayer::setCallbackEventPosition(RecorderCallbackPosition f) {
callbackPosition = std::move(f);
}
void Replayer::setCallbackEventFinish(RecorderCallbackFinish f) {
callbackFinish = std::move(f);
}
void Replayer::setCallbackStateTrafficLight(RecorderCallbackStateTrafficLight f) {
callbackStateTrafficLight = std::move(f);
}
void Replayer::stop(bool keepActors) {
if (enabled) {
enabled = false;
if (!keepActors)
processToTime(totalTime);
file.close();
// callback
if (callbackFinish)
callbackFinish(keepActors);
}
if (!keepActors)
log_warning("Replayer stop");
else
log_warning("Replayer stop (keeping actors)");
}
bool Replayer::readHeader() {
if (file.eof()) {
return false;
}
readValue<char>(file, header.id);
readValue<uint32_t>(file, header.size);
return true;
}
void Replayer::skipPacket() {
file.seekg(header.size, std::ios::cur);
}
std::string Replayer::getInfo(std::string filename) {
std::stringstream info;
// try to open
file.open(filename, std::ios::binary);
if (!file.is_open()) {
info << "File " << filename << " not found on server\n";
return info.str();
}
uint16_t i, total;
RecorderEventAdd eventAdd;
RecorderEventDel eventDel;
RecorderEventParent eventParent;
// RecorderStateTrafficLight stateTraffic;
bool bShowFrame;
// read info
recInfo.read(file);
// check magic string
std::string magic;
magic.resize(recInfo.magic.size());
std::copy(recInfo.magic.begin(), recInfo.magic.end(), magic.begin());
if (magic != "CARLA_RECORDER") {
info << "File is not a CARLA recorder" << std::endl;
return info.str();
}
// show general info
info << "Version: " << recInfo.version << std::endl;
info << "Map: " << recInfo.mapfile.data() << std::endl;
tm *timeInfo = localtime(&recInfo.date);
char dateStr[100];
strftime(dateStr, 100, "%x %X", timeInfo);
info << "Date: " << dateStr << std::endl << std::endl;
// parse only frames
while (file) {
// get header
if (!readHeader()) {
break;
}
// check for a frame packet
switch (header.id) {
case static_cast<char>(RecorderPacketId::Frame):
frame.read(file);
// info << "Frame " << frame.id << " at " << frame.elapsed << "
// seconds\n";
break;
case static_cast<char>(RecorderPacketId::Event):
bShowFrame = true;
readValue<uint16_t>(file, total);
if (total > 0 && bShowFrame) {
info << "Frame " << frame.id << " at " << frame.elapsed << " seconds\n";
bShowFrame = false;
}
for (i = 0; i < total; ++i) {
eventAdd.read(file);
// convert buffer to string to show
std::string s("");
s.resize(eventAdd.description.id.size());
std::copy(eventAdd.description.id.begin(), eventAdd.description.id.end(), s.begin());
info << " Create " << eventAdd.databaseId << ": " << s.data() << " (" <<
eventAdd.description.uid << ") at (" << eventAdd.transform.location.x << ", " <<
eventAdd.transform.location.y << ", " << eventAdd.transform.location.z << ")" << std::endl;
for (auto &att : eventAdd.description.attributes) {
std::string s1(""), s2("");
s1.resize(att.id.size());
std::copy(att.id.begin(), att.id.end(), s1.begin());
s2.resize(att.value.size());
std::copy(att.value.begin(), att.value.end(), s2.begin());
info << " " << s1.data() << " = " << s2.data() << std::endl;
}
}
readValue<uint16_t>(file, total);
if (total > 0 && bShowFrame) {
info << "Frame " << frame.id << " at " << frame.elapsed << " seconds\n";
bShowFrame = false;
}
for (i = 0; i < total; ++i) {
eventDel.read(file);
info << " Destroy " << eventDel.databaseId << "\n";
}
readValue<uint16_t>(file, total);
if (total > 0 && bShowFrame) {
info << "Frame " << frame.id << " at " << frame.elapsed << " seconds\n";
bShowFrame = false;
}
for (i = 0; i < total; ++i) {
eventParent.read(file);
info << " Parenting " << eventParent.databaseId << " with " << eventDel.databaseId <<
" (parent)\n";
}
break;
case static_cast<char>(RecorderPacketId::Position):
// info << "Positions\n";
skipPacket();
break;
case static_cast<char>(RecorderPacketId::State):
skipPacket();
// bShowFrame = true;
// readValue<uint16_t>(file, total);
//if (total > 0 && bShowFrame) {
// info << "Frame " << frame.id << " at " << frame.elapsed << " seconds\n";
// bShowFrame = false;
//}
//info << " State traffic lights: " << total << std::endl;
//for (i = 0; i < total; ++i) {
// stateTraffic.read(file);
// info << " Id: " << stateTraffic.databaseId << " state: " << static_cast<char>(0x30 + stateTraffic.state) << " frozen: " << stateTraffic.isFrozen << " elapsedTime: " << stateTraffic.elapsedTime << std::endl;
// }
break;
default:
// skip packet
info << "Unknown packet id: " << header.id << " at offset " << file.tellg() << std::endl;
skipPacket();
break;
}
}
info << "\nFrames: " << frame.id << "\n";
info << "Duration: " << frame.elapsed << " seconds\n";
file.close();
return info.str();
}
void Replayer::rewind(void) {
currentTime = 0.0f;
totalTime = 0.0f;
timeToStop = 0.0f;
file.clear();
file.seekg(0, std::ios::beg);
// mark as header as invalid to force reload a new one next time
frame.elapsed = -1.0f;
frame.durationThis = 0.0f;
mappedId.clear();
// read geneal info
recInfo.read(file);
// log_warning("Replayer rewind");
}
// read last frame in file and return the total time recorded
double Replayer::getTotalTime(void) {
std::streampos current = file.tellg();
// parse only frames
while (file) {
// get header
if (!readHeader())
break;
// check for a frame packet
switch (header.id) {
case static_cast<char>(RecorderPacketId::Frame):
frame.read(file);
break;
default:
skipPacket();
break;
}
}
file.clear();
file.seekg(current, std::ios::beg);
return frame.elapsed;
}
std::string Replayer::replayFile(std::string filename, double timeStart, double duration) {
std::stringstream info;
std::string s;
// check to stop if we are replaying another
if (enabled) {
stop();
}
info << "Replaying file: " << filename << std::endl;
// try to open
file.open(filename, std::ios::binary);
if (!file.is_open()) {
info << "File " << filename << " not found on server\n";
return info.str();
}
// from start
rewind();
// get total time of recorder
totalTime = getTotalTime();
info << "Total time recorded: " << totalTime << std::endl;
// set time to start replayer
if (timeStart < 0.0f) {
timeStart = totalTime + timeStart;
if (timeStart < 0.0f) timeStart = 0.0f;
}
// set time to stop replayer
if (duration > 0.0f)
timeToStop = timeStart + duration;
else
timeToStop = totalTime;
info << "Replaying from " << timeStart << " s - " << timeToStop << " s (" << totalTime << " s)" << std::endl;
// process all events until the time
processToTime(timeStart);
// mark as enabled
enabled = true;
return info.str();
}
void Replayer::processToTime(double time) {
double per = 0.0f;
double newTime = currentTime + time;
bool frameFound = false;
// check if we are in the right frame
if (newTime >= frame.elapsed && newTime < frame.elapsed + frame.durationThis) {
per = (newTime - frame.elapsed) / frame.durationThis;
frameFound = true;
}
// process all frames until time we want or end
while (!file.eof() && !frameFound) {
// get header
readHeader();
// check it is a frame packet
if (header.id != static_cast<char>(RecorderPacketId::Frame)) {
if (!file.eof())
log_error("Replayer file error: waitting for a Frame packet");
stop();
break;
}
// read current frame
frame.read(file);
// check if target time is in this frame
if (frame.elapsed + frame.durationThis < newTime) {
per = 0.0f;
} else {
per = (newTime - frame.elapsed) / frame.durationThis;
frameFound = true;
}
// info << "Frame: " << frame.id << " (" << frame.durationThis << " / " <<
// frame.elapsed << ") per: " << per << std::endl;
// get header
readHeader();
// check it is an events packet
if (header.id != static_cast<char>(RecorderPacketId::Event)) {
log_error("Replayer file error: waitting for an Event packet");
stop();
break;
}
processEvents();
// get header
readHeader();
// check it is a positions packet
if (header.id != static_cast<char>(RecorderPacketId::Position)) {
log_error("Replayer file error: waitting for a Position packet");
stop();
break;
}
if (frameFound) {
processPositions();
} else {
skipPacket();
}
// get header
readHeader();
// check it is an state packet
if (header.id != static_cast<char>(RecorderPacketId::State)) {
log_error("Replayer file error: waitting for an State packet");
stop();
break;
}
if (frameFound) {
processStates();
} else {
skipPacket();
}
// log_warning("Replayer new frame");
}
// update all positions
if (enabled && frameFound)
updatePositions(per);
// save current time
currentTime = newTime;
// stop replay?
if (currentTime >= timeToStop) {
// check if we need to stop the replayer and let it continue in simulation mode
if (timeToStop == totalTime)
stop();
else
stop(true); // keep actors in scene so they continue with AI
}
}
void Replayer::processEvents(void) {
uint16_t i, total;
RecorderEventAdd eventAdd;
RecorderEventDel eventDel;
RecorderEventParent eventParent;
std::stringstream info;
// create events
readValue<uint16_t>(file, total);
for (i = 0; i < total; ++i) {
std::string s;
eventAdd.read(file);
// avoid sensor events
if (memcmp(eventAdd.description.id.data(), "sensor.", 7) != 0) {
// show log
s.resize(eventAdd.description.id.size());
std::copy(eventAdd.description.id.begin(), eventAdd.description.id.end(), s.begin());
info.str("");
info << "Create " << eventAdd.databaseId << " (" << eventAdd.description.uid << ") " << s.data() <<
std::endl;
for (const auto &att : eventAdd.description.attributes) {
std::string s2;
s.resize(att.id.size());
std::copy(att.id.begin(), att.id.end(), s.begin());
s2.resize(att.value.size());
std::copy(att.value.begin(), att.value.end(), s2.begin());
info << " " << s.data() << " = " << s2.data() << std::endl;
}
log_warning(info.str());
// callback
if (callbackEventAdd) {
// log_warning("calling callback add");
auto result = callbackEventAdd(eventAdd.transform,
std::move(eventAdd.description),
eventAdd.databaseId);
switch (result.first) {
case 0:
log_warning("actor could not be created");
break;
case 1:
if (result.second != eventAdd.databaseId) {
log_warning("actor created but with different id");
}
// mapping id (recorded Id is a new Id in replayer)
mappedId[eventAdd.databaseId] = result.second;
break;
case 2:
log_warning("actor already exist, not created");
// mapping id (say desired Id is mapped to what)
mappedId[eventAdd.databaseId] = result.second;
break;
}
} else {
log_warning("callback add is not defined");
}
}
}
// destroy events
readValue<uint16_t>(file, total);
for (i = 0; i < total; ++i) {
eventDel.read(file);
info.str("");
info << "Destroy " << mappedId[eventDel.databaseId] << "\n";
log_warning(info.str());
// callback
if (callbackEventDel) {
callbackEventDel(mappedId[eventDel.databaseId]);
mappedId.erase(eventDel.databaseId);
} else {
log_warning("callback del is not defined");
}
}
// parenting events
readValue<uint16_t>(file, total);
for (i = 0; i < total; ++i) {
eventParent.read(file);
info.str("");
info << "Parenting " << mappedId[eventParent.databaseId] << " with " << mappedId[eventDel.databaseId] <<
" (parent)\n";
log_warning(info.str());
// callback
if (callbackEventParent) {
callbackEventParent(mappedId[eventParent.databaseId], mappedId[eventParent.databaseIdParent]);
} else {
log_warning("callback parent is not defined");
}
}
}
void Replayer::processStates(void) {
uint16_t i, total;
RecorderStateTrafficLight stateTrafficLight;
std::stringstream info;
// read total traffic light states
readValue<uint16_t>(file, total);
for (i = 0; i < total; ++i) {
stateTrafficLight.read(file);
// callback
if (callbackStateTrafficLight) {
// log_warning("calling callback add");
stateTrafficLight.databaseId = mappedId[stateTrafficLight.databaseId];
if (!callbackStateTrafficLight(stateTrafficLight))
log_warning("callback state traffic light %d called but didn't work", stateTrafficLight.databaseId);
} else {
log_warning("callback state traffic light is not defined");
}
}
}
void Replayer::processPositions(void) {
uint16_t i, total;
// save current as previous
prevPos = std::move(currPos);
// read all positions
readValue<uint16_t>(file, total);
currPos.clear();
currPos.reserve(total);
for (i = 0; i < total; ++i) {
RecorderPosition pos;
pos.read(file);
// assign mapped Id
auto newId = mappedId.find(pos.databaseId);
if (newId != mappedId.end()) {
pos.databaseId = newId->second;
}
currPos.push_back(std::move(pos));
}
}
void Replayer::updatePositions(double per) {
unsigned int i;
std::unordered_map<int, int> tempMap;
// map the id of all previous positions to its index
for (i = 0; i < prevPos.size(); ++i) {
tempMap[prevPos[i].databaseId] = i;
}
// go through each actor and update
for (i = 0; i < currPos.size(); ++i) {
// check if exist a previous position
auto result = tempMap.find(currPos[i].databaseId);
if (result != tempMap.end()) {
// interpolate
interpolatePosition(prevPos[result->second], currPos[i], per);
} else {
// assign last position (we don't have previous one)
interpolatePosition(currPos[i], currPos[i], 0);
// log_warning("Interpolation not possible, only one position");
}
}
}
// interpolate a position (transform, velocity...)
void Replayer::interpolatePosition(
const RecorderPosition &prevPos,
const RecorderPosition &currPos,
double per) {
// call the callback
callbackPosition(prevPos, currPos, per);
}
// tick for the replayer
void Replayer::tick(float delta) {
// check if there are events to process
if (enabled) {
processToTime(delta);
}
// log_warning("Replayer tick");
}
} // namespace recorder
} // namespace carla

View File

@ -1,109 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include <sstream>
#include <functional>
#include "carla/NonCopyable.h"
//#include "carla/recorder/Recorder.h"
#include "carla/recorder/RecorderInfo.h"
#include "carla/recorder/RecorderFrames.h"
#include "carla/recorder/RecorderEvent.h"
#include "carla/recorder/RecorderPosition.h"
#include "carla/recorder/RecorderState.h"
#include "carla/recorder/RecorderHelpers.h"
namespace carla {
namespace recorder {
// callback prototypes
typedef std::function<std::pair<int, uint32_t> (carla::geom::Transform, RecorderActorDescription, uint32_t uid)> RecorderCallbackEventAdd;
typedef std::function<bool (uint32_t uid)> RecorderCallbackEventDel;
typedef std::function<bool (uint32_t childId, uint32_t parentId)> RecorderCallbackEventParent;
typedef std::function<bool (RecorderPosition pos1, RecorderPosition pos2, double per)> RecorderCallbackPosition;
typedef std::function<bool (bool applyAutopilot)> RecorderCallbackFinish;
typedef std::function<bool (RecorderStateTrafficLight state)> RecorderCallbackStateTrafficLight;
#pragma pack(push, 1)
struct Header {
char id;
uint32_t size;
};
#pragma pack(pop)
class Replayer : private NonCopyable {
public:
Replayer();
~Replayer();
std::string getInfo(std::string filename);
std::string replayFile(std::string filename, double timeStart = 0.0f, double duration = 0.0f);
//void start(void);
void stop(bool keepActors = false);
void enable(void);
void disable(void);
bool isEnabled(void) { return enabled; };
// callbacks
void setCallbackEventAdd(RecorderCallbackEventAdd f);
void setCallbackEventDel(RecorderCallbackEventDel f);
void setCallbackEventParent(RecorderCallbackEventParent f);
void setCallbackEventPosition(RecorderCallbackPosition f);
void setCallbackEventFinish(RecorderCallbackFinish f);
void setCallbackStateTrafficLight(RecorderCallbackStateTrafficLight f);
// tick for the replayer
void tick(float time);
private:
bool enabled;
// binary file reader
std::ifstream file;
Header header;
RecorderInfo recInfo;
RecorderFrame frame;
// callbacks
RecorderCallbackEventAdd callbackEventAdd;
RecorderCallbackEventDel callbackEventDel;
RecorderCallbackEventParent callbackEventParent;
RecorderCallbackPosition callbackPosition;
RecorderCallbackFinish callbackFinish;
RecorderCallbackStateTrafficLight callbackStateTrafficLight;
// positions (to be able to interpolate)
std::vector<RecorderPosition> currPos;
std::vector<RecorderPosition> prevPos;
// mapping id
std::unordered_map<uint32_t, uint32_t> mappedId;
// times
double currentTime;
double timeToStop;
double totalTime;
// utils
bool readHeader();
void skipPacket();
double getTotalTime(void);
void rewind(void);
// processing packets
void processToTime(double time);
void processEvents(void);
void processPositions(void);
void processStates(void);
// positions
void updatePositions(double per);
void interpolatePosition(const RecorderPosition &start, const RecorderPosition &end, double per);
};
}
}

View File

@ -23,7 +23,7 @@ void export_client() {
.def("get_server_version", CONST_CALL_WITHOUT_GIL(cc::Client, GetServerVersion))
.def("get_world", &cc::Client::GetWorld)
.def("start_recorder", &cc::Client::StartRecorder, (arg("name")))
.def("stop_recorder", CALL_WITHOUT_GIL(cc::Client, StopRecorder))
.def("stop_recorder", &cc::Client::StopRecorder)
.def("show_recorder_file_info", &cc::Client::ShowRecorderFileInfo, (arg("name")))
.def("replay_file", &cc::Client::ReplayFile, (arg("name"), arg("time_start"), arg("duration")))

View File

@ -14,14 +14,11 @@
#include "EngineUtils.h"
#include "GameFramework/SpectatorPawn.h"
#include <compiler/disable-ue4-macros.h>
#include <carla/recorder/Recorder.h>
#include <compiler/enable-ue4-macros.h>
static FString UCarlaEpisode_GetTrafficSignId(ETrafficSignState State)
{
using TSS = ETrafficSignState;
switch (State) {
switch (State)
{
case TSS::TrafficLightRed:
case TSS::TrafficLightYellow:
case TSS::TrafficLightGreen: return TEXT("traffic.traffic_light");
@ -40,16 +37,17 @@ static FString UCarlaEpisode_GetTrafficSignId(ETrafficSignState State)
UCarlaEpisode::UCarlaEpisode(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer),
Id([]() {
static uint32 COUNTER = 0u;
return ++COUNTER;
}()) {
static uint32 COUNTER = 0u;
return ++COUNTER;
} ()) {
ActorDispatcher = CreateDefaultSubobject<UActorDispatcher>(TEXT("ActorDispatcher"));
}
TArray<FTransform> UCarlaEpisode::GetRecommendedSpawnPoints() const
{
TArray<FTransform> SpawnPoints;
for (TActorIterator<AVehicleSpawnPoint> It(GetWorld()); It; ++It) {
for (TActorIterator<AVehicleSpawnPoint> It(GetWorld()); It; ++It)
{
SpawnPoints.Add(It->GetActorTransform());
}
return SpawnPoints;
@ -66,7 +64,9 @@ carla::rpc::Actor UCarlaEpisode::SerializeActor(FActorView ActorView) const
{
Actor.parent_id = FindActor(Parent).GetActorId();
}
} else {
}
else
{
UE_LOG(LogCarla, Warning, TEXT("Trying to serialize invalid actor"));
}
return Actor;
@ -80,12 +80,14 @@ void UCarlaEpisode::AttachActors(AActor *Child, AActor *Parent)
Child->SetOwner(Parent);
// recorder event
if (Recorder.isEnabled()) {
crec::RecorderEventParent recEvent {
if (Recorder->IsEnabled())
{
CarlaRecorderEventParent RecEvent
{
FindActor(Child).GetActorId(),
FindActor(Parent).GetActorId()
};
Recorder.addEvent(std::move(recEvent));
Recorder->AddEvent(std::move(RecEvent));
}
}
@ -123,32 +125,36 @@ void UCarlaEpisode::InitializeAtBeginPlay()
}
// replayer callbacks
Recorder.getReplayer().setCallbackEventAdd([this](carla::geom::Transform transform,
carla::recorder::RecorderActorDescription description, uint32_t desiredId) -> std::pair<int, uint32_t> {
Recorder->GetReplayer()->SetCallbackEventAdd([this](FVector Location, FVector Rotation,
CarlaRecorderActorDescription Description, uint32_t DesiredId) -> std::pair<int, uint32_t> {
FActorDescription ActorDesc;
ActorDesc.UId = description.uid;
ActorDesc.Id = FString(description.id.size(), UTF8_TO_TCHAR(description.id.data()));
for (const auto &item : description.attributes) {
FActorAttribute attr;
attr.Type = static_cast<EActorAttributeType>(item.type);
attr.Id = FString(item.id.size(), UTF8_TO_TCHAR(item.id.data()));
attr.Value = FString(item.value.size(), UTF8_TO_TCHAR(item.value.data()));
ActorDesc.Variations.Add(attr.Id, std::move(attr));
ActorDesc.UId = Description.UId;
ActorDesc.Id = Description.Id;
for (const auto &Item : Description.Attributes)
{
FActorAttribute Attr;
Attr.Type = static_cast<EActorAttributeType>(Item.Type);
Attr.Id = Item.Id;
Attr.Value = Item.Value;
ActorDesc.Variations.Add(Attr.Id, std::move(Attr));
}
auto result = TryToCreateReplayerActor(transform, ActorDesc, desiredId);
auto result = TryToCreateReplayerActor(Location, Rotation, ActorDesc, DesiredId);
if (result.first != 0) {
if (result.first != 0)
{
// disable physics
// SetActorSimulatePhysics(result.second, false);
// disable autopilot
auto Vehicle = Cast<ACarlaWheeledVehicle>(result.second.GetActor());
if (Vehicle != nullptr) {
if (Vehicle != nullptr)
{
auto Controller = Cast<AWheeledVehicleAIController>(Vehicle->GetController());
if (Controller != nullptr) {
if (Controller != nullptr)
{
Controller->SetAutopilot(false);
UE_LOG(LogCarla, Log, TEXT("resetting autopilot to %d"), desiredId);
UE_LOG(LogCarla, Log, TEXT("resetting autopilot to %d"), DesiredId);
}
}
}
@ -156,222 +162,232 @@ void UCarlaEpisode::InitializeAtBeginPlay()
return std::make_pair(result.first, result.second.GetActorId());
});
// callback
Recorder.getReplayer().setCallbackEventDel([this](uint32_t databaseId) -> bool {
auto actor = GetActorRegistry().Find(databaseId).GetActor();
if (actor == nullptr) return false;
DestroyActor(actor);
// callback
Recorder->GetReplayer()->SetCallbackEventDel([this](uint32_t DatabaseId) -> bool {
auto actor = GetActorRegistry().Find(DatabaseId).GetActor();
if (actor == nullptr)
{
return false;
}
DestroyActor(actor);
return true;
});
// callback
Recorder->GetReplayer()->SetCallbackEventParent([this](uint32_t ChildId, uint32_t ParentId) -> bool {
AActor *child = GetActorRegistry().Find(ChildId).GetActor();
AActor *parent = GetActorRegistry().Find(ParentId).GetActor();
if (child && parent)
{
child->AttachToActor(parent, FAttachmentTransformRules::KeepRelativeTransform);
child->SetOwner(parent);
UE_LOG(LogCarla, Log, TEXT("Parenting Actor"));
return true;
});
}
else
{
UE_LOG(LogCarla, Log, TEXT("Parenting Actors not found"));
return false;
}
});
// callback
Recorder.getReplayer().setCallbackEventParent([this](uint32_t childId, uint32_t parentId) -> bool {
AActor *child = GetActorRegistry().Find(childId).GetActor();
AActor *parent = GetActorRegistry().Find(parentId).GetActor();
if (child && parent) {
child->AttachToActor(parent, FAttachmentTransformRules::KeepRelativeTransform);
child->SetOwner(parent);
UE_LOG(LogCarla, Log, TEXT("Parenting Actor"));
return true;
}
else {
UE_LOG(LogCarla, Log, TEXT("Parenting Actors not found"));
return false;
}
});
// callback
Recorder->GetReplayer()->SetCallbackEventPosition([this](CarlaRecorderPosition Pos1,
CarlaRecorderPosition Pos2, double Per) -> bool {
AActor *actor = GetActorRegistry().Find(Pos1.DatabaseId).GetActor();
if (actor && !actor->IsPendingKill())
{
// interpolate transform
FVector Location = FMath::Lerp(FVector(Pos1.Location), FVector(Pos2.Location), Per);
FRotator Rotation =
FMath::Lerp(FRotator::MakeFromEuler(Pos1.Rotation), FRotator::MakeFromEuler(Pos2.Rotation), Per);
FTransform Trans(Rotation, Location, FVector(1, 1, 1));
actor->SetActorRelativeTransform(Trans, false, nullptr, ETeleportType::TeleportPhysics);
return true;
}
return false;
});
// callback
Recorder.getReplayer().setCallbackEventPosition([this](carla::recorder::RecorderPosition pos1,
carla::recorder::RecorderPosition pos2, double per) -> bool {
AActor *actor = GetActorRegistry().Find(pos1.databaseId).GetActor();
if (actor && !actor->IsPendingKill())
// callback
Recorder->GetReplayer()->SetCallbackStateTrafficLight([this](CarlaRecorderStateTrafficLight State) -> bool {
AActor *Actor = GetActorRegistry().Find(State.DatabaseId).GetActor();
if (Actor && !Actor->IsPendingKill())
{
auto TrafficLight = Cast<ATrafficLightBase>(Actor);
if (TrafficLight != nullptr)
{
// interpolate transform
FVector location = FMath::Lerp(FVector(pos1.transform.location), FVector(pos2.transform.location), per);
FRotator rotation = FMath::Lerp(FRotator(pos1.transform.rotation), FRotator(pos2.transform.rotation), per);
FTransform trans(rotation, location, FVector(1,1,1));
actor->SetActorRelativeTransform(trans, false, nullptr, ETeleportType::TeleportPhysics);
return true;
TrafficLight->SetTrafficLightState(static_cast<ETrafficLightState>(State.State));
TrafficLight->SetTimeIsFrozen(State.IsFrozen);
TrafficLight->SetElapsedTime(State.ElapsedTime);
}
return false;
});
// callback
Recorder.getReplayer().setCallbackStateTrafficLight([this](carla::recorder::RecorderStateTrafficLight state) -> bool {
AActor *Actor = GetActorRegistry().Find(state.databaseId).GetActor();
if (Actor && !Actor->IsPendingKill()) {
auto TrafficLight = Cast<ATrafficLightBase>(Actor);
if (TrafficLight != nullptr)
{
TrafficLight->SetTrafficLightState(static_cast<ETrafficLightState>(state.state));
TrafficLight->SetTimeIsFrozen(state.isFrozen);
TrafficLight->SetElapsedTime(state.elapsedTime);
}
return true;
}
return false;
});
// callback
Recorder.getReplayer().setCallbackEventFinish([this](bool applyAutopilot) -> bool {
if (!applyAutopilot)
return false;
// set autopilo to all AI vehicles
auto registry = GetActorRegistry();
for (auto &&ActorView : registry) {
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
continue;
}
auto Vehicle = Cast<ACarlaWheeledVehicle>(ActorView.GetActor());
if (Vehicle == nullptr) {
continue;
}
// SetActorSimulatePhysics(ActorView, true);
auto Controller = Cast<AWheeledVehicleAIController>(Vehicle->GetController());
if (Controller == nullptr) {
continue;
}
Controller->SetAutopilot(true);
UE_LOG(LogCarla, Log, TEXT("setting autopilot to %d"), ActorView.GetActorId());
}
return true;
});
}
return false;
});
// callback
Recorder->GetReplayer()->SetCallbackEventFinish([this](bool applyAutopilot) -> bool {
if (!applyAutopilot)
{
return false;
}
// set autopilo to all AI vehicles
auto registry = GetActorRegistry();
for (auto &&ActorView : registry)
{
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
continue;
}
auto Vehicle = Cast<ACarlaWheeledVehicle>(ActorView.GetActor());
if (Vehicle == nullptr)
{
continue;
}
// SetActorSimulatePhysics(ActorView, true);
auto Controller = Cast<AWheeledVehicleAIController>(Vehicle->GetController());
if (Controller == nullptr)
{
continue;
}
Controller->SetAutopilot(true);
UE_LOG(LogCarla, Log, TEXT("setting autopilot to %d"), ActorView.GetActorId());
}
return true;
});
}
void UCarlaEpisode::EndPlay(void) {
void UCarlaEpisode::EndPlay(void)
{
// stop recorder and replayer
if (Recorder.isEnabled())
Recorder.stop();
if (Recorder.getReplayer().isEnabled())
Recorder.getReplayer().stop();
if (Recorder)
{
Recorder->Stop();
if (Recorder->GetReplayer()->IsEnabled())
{
Recorder->GetReplayer()->Stop();
}
}
}
bool UCarlaEpisode::SetActorSimulatePhysics(FActorView &ActorView, bool bEnabled) {
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill()) {
bool UCarlaEpisode::SetActorSimulatePhysics(FActorView &ActorView, bool bEnabled)
{
if (!ActorView.IsValid() || ActorView.GetActor()->IsPendingKill())
{
return false;
}
auto RootComponent = Cast<UPrimitiveComponent>(ActorView.GetActor()->GetRootComponent());
if (RootComponent == nullptr) {
return false; // unable to set actor simulate physics: not supported by actor
if (RootComponent == nullptr)
{
return false; // unable to set actor simulate physics: not supported by
// actor
}
RootComponent->SetSimulatePhysics(bEnabled);
return true;
}
std::string UCarlaEpisode::StartRecorder(std::string name) {
std::string UCarlaEpisode::StartRecorder(std::string Name)
{
std::string result;
FString Name2(Name.c_str());
// start
result = Recorder.start(carla::rpc::FromFString(FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir())), name, carla::rpc::FromFString(MapName));
// registring all existing actors in first frame
FActorRegistry Registry = GetActorRegistry();
for (auto &&View : Registry) {
const AActor *actor = View.GetActor();
check(actor != nullptr);
// create event
CreateRecorderEventAdd(
View.GetActorId(),
actor->GetActorTransform(),
View.GetActorInfo()->Description
);
};
if (Recorder)
{
result = Recorder->Start(FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir()), Name2, MapName);
}
else
{
result = "Recorder is not ready";
}
return result;
}
void UCarlaEpisode::CreateRecorderEventAdd(
uint32_t databaseId,
const FTransform &Transform,
FActorDescription thisActorDescription)
{
// convert from FActorDescription to crec::RecorderActorDescription
crec::RecorderActorDescription description;
description.uid = thisActorDescription.UId;
description.id.copy_from(carla::rpc::FromFString(thisActorDescription.Id));
description.attributes.reserve(thisActorDescription.Variations.Num());
for (const auto &item : thisActorDescription.Variations) {
crec::RecorderActorAttribute attr;
attr.type = static_cast<carla::rpc::ActorAttributeType>(item.Value.Type);
attr.id.copy_from(carla::rpc::FromFString(item.Value.Id));
attr.value.copy_from(carla::rpc::FromFString(item.Value.Value));
// check for empty attributes
if (attr.id.size() > 0)
description.attributes.emplace_back(std::move(attr));
}
// recorder event
crec::RecorderEventAdd recEvent {
databaseId,
Transform,
std::move(description)
};
Recorder.addEvent(std::move(recEvent));
}
// create or reuse an actor for replaying
std::pair<int, FActorView&> UCarlaEpisode::TryToCreateReplayerActor(carla::geom::Transform &transform, FActorDescription &ActorDesc, uint32_t desiredId) {
std::pair<int, FActorView &> UCarlaEpisode::TryToCreateReplayerActor(
FVector &Location,
FVector &Rotation,
FActorDescription &ActorDesc,
uint32_t DesiredId)
{
FActorView view_empty;
// check type of actor we need
if (ActorDesc.Id.StartsWith("traffic.")) {
if (ActorDesc.Id.StartsWith("traffic."))
{
auto World = GetWorld();
check(World != nullptr);
// get its position (truncated as int's, and in Cm)
int x = static_cast<int>(transform.location.x);
int y = static_cast<int>(transform.location.y);
int z = static_cast<int>(transform.location.z);
UE_LOG(LogCarla, Log, TEXT("Trying to find traffic: %s (%d) [%d,%d,%d]"), *ActorDesc.Id, desiredId, x, y, z);
int x = static_cast<int>(Location.X);
int y = static_cast<int>(Location.Y);
int z = static_cast<int>(Location.Z);
UE_LOG(LogCarla,
Log,
TEXT("Trying to find traffic: %s (%d) [%d,%d,%d]"),
*ActorDesc.Id,
DesiredId,
x,
y,
z);
// search an "traffic." actor at that position
for (TActorIterator<ATrafficSignBase> It(World); It; ++It)
{
ATrafficSignBase *Actor = *It;
check(Actor != nullptr);
FVector vec = Actor->GetTransform().GetTranslation();
int x2 = static_cast<int>(vec.X / 100.0f);
int y2 = static_cast<int>(vec.Y / 100.0f);
int z2 = static_cast<int>(vec.Z / 100.0f);
// UE_LOG(LogCarla, Log, TEXT(" Checking with [%d,%d,%d]"), x2, y2, z2);
if ((x2 == x) && (y2 == y) && (z2 == z)) {
int x2 = static_cast<int>(vec.X);
int y2 = static_cast<int>(vec.Y);
int z2 = static_cast<int>(vec.Z);
UE_LOG(LogCarla, Log, TEXT(" Checking with [%d,%d,%d]"), x2, y2, z2);
if ((x2 == x) && (y2 == y) && (z2 == z))
{
// actor found
auto view = ActorDispatcher->GetActorRegistry().Find(static_cast<AActor *>(Actor));
// reuse that actor
UE_LOG(LogCarla, Log, TEXT("Traffic found with id: %d"), view.GetActorId());
return std::pair<int, FActorView&>(2, view);
return std::pair<int, FActorView &>(2, view);
}
}
// actor not found
UE_LOG(LogCarla, Log, TEXT("Traffic not found"));
return std::pair<int, FActorView&>(0, view_empty);
} else if (ActorDesc.Id.StartsWith("vehicle.")) {
return std::pair<int, FActorView &>(0, view_empty);
}
else if (ActorDesc.Id.StartsWith("vehicle."))
{
// check if an actor of that type already exist with same id
UE_LOG(LogCarla, Log, TEXT("Trying to create actor: %s (%d)"), *ActorDesc.Id, desiredId);
if (GetActorRegistry().Contains(desiredId)) {
auto view = GetActorRegistry().Find(desiredId);
UE_LOG(LogCarla, Log, TEXT("Trying to create actor: %s (%d)"), *ActorDesc.Id, DesiredId);
if (GetActorRegistry().Contains(DesiredId))
{
auto view = GetActorRegistry().Find(DesiredId);
const FActorDescription *desc = &view.GetActorInfo()->Description;
UE_LOG(LogCarla, Log, TEXT("actor '%s' already exist with id %d"), *(desc->Id), view.GetActorId());
if (desc->Id == ActorDesc.Id) {
if (desc->Id == ActorDesc.Id)
{
// we don't need to create, actor of same type already exist
return std::pair<int, FActorView&>(2, view);
return std::pair<int, FActorView &>(2, view);
}
}
// create the transform
FRotator Rot = FRotator::MakeFromEuler(Rotation);
FTransform Trans(Rot, Location, FVector(1, 1, 1));
// create as new actor
TPair<EActorSpawnResultStatus, FActorView> Result = SpawnActorWithInfo(transform, ActorDesc, desiredId);
if (Result.Key == EActorSpawnResultStatus::Success) {
TPair<EActorSpawnResultStatus, FActorView> Result = SpawnActorWithInfo(Trans, ActorDesc, DesiredId);
if (Result.Key == EActorSpawnResultStatus::Success)
{
UE_LOG(LogCarla, Log, TEXT("Actor created by replayer with id %d"), Result.Value.GetActorId());
return std::pair<int, FActorView&>(1, Result.Value);
return std::pair<int, FActorView &>(1, Result.Value);
}
else {
else
{
UE_LOG(LogCarla, Log, TEXT("Actor could't be created by replayer"));
return std::pair<int, FActorView&>(0, Result.Value);
return std::pair<int, FActorView &>(0, Result.Value);
}
}
else {
else
{
// actor ignored
return std::pair<int, FActorView&>(0, view_empty);
return std::pair<int, FActorView &>(0, view_empty);
}
}

View File

@ -10,21 +10,17 @@
#include "Carla/Sensor/WorldObserver.h"
#include "Carla/Weather/Weather.h"
#include "Carla/Server/TheNewCarlaServer.h"
#include "Carla/Game/CarlaRecorder.h"
#include <compiler/disable-ue4-macros.h>
#include <carla/rpc/Actor.h>
#include <carla/rpc/ActorDescription.h>
#include <carla/geom/BoundingBox.h>
#include <carla/recorder/Recorder.h>
#include <carla/recorder/RecorderEvent.h>
#include <carla/recorder/Replayer.h>
#include <carla/streaming/Server.h>
#include <compiler/enable-ue4-macros.h>
#include "CarlaEpisode.generated.h"
namespace crec = carla::recorder;
/// A simulation episode.
///
/// Each time the level is restarted a new episode is created.
@ -152,16 +148,18 @@ public:
FActorView::IdType DesiredId = 0)
{
auto result = ActorDispatcher->SpawnActor(Transform, thisActorDescription, DesiredId);
if (Recorder.isEnabled()) {
if (result.Key == EActorSpawnResultStatus::Success) {
CreateRecorderEventAdd(
static_cast<carla::rpc::actor_id_type>(result.Value.GetActorId()),
if (Recorder->IsEnabled())
{
if (result.Key == EActorSpawnResultStatus::Success)
{
Recorder->CreateRecorderEventAdd(
result.Value.GetActorId(),
Transform,
std::move(thisActorDescription)
);
}
}
return result;
}
@ -189,12 +187,14 @@ public:
UFUNCTION(BlueprintCallable)
bool DestroyActor(AActor *Actor)
{
if (Recorder.isEnabled()) {
if (Recorder->IsEnabled())
{
// recorder event
crec::RecorderEventDel recEvent {
GetActorRegistry().Find(Actor).GetActorId(),
CarlaRecorderEventDel RecEvent
{
GetActorRegistry().Find(Actor).GetActorId()
};
Recorder.addEvent(std::move(recEvent));
Recorder->AddEvent(std::move(RecEvent));
}
return ActorDispatcher->DestroyActor(Actor);
@ -213,14 +213,19 @@ public:
// -- Private methods and members --------------------------------------------
// ===========================================================================
crec::Recorder &GetRecorder()
ACarlaRecorder *GetRecorder()
{
return Recorder;
}
crec::Replayer &GetReplayer()
void SetRecorder(ACarlaRecorder *Rec)
{
return Recorder.getReplayer();
Recorder = Rec;
}
CarlaReplayer *GetReplayer()
{
return Recorder->GetReplayer();
}
std::string StartRecorder(std::string name);
@ -237,13 +242,9 @@ private:
ActorDispatcher->Bind(ActorFactory);
}
void CreateRecorderEventAdd(
unsigned int databaseId,
const FTransform &Transform,
FActorDescription thisActorDescription);
std::pair<int, FActorView&> TryToCreateReplayerActor(
carla::geom::Transform &transform,
FVector &Location,
FVector &Rotation,
FActorDescription &ActorDesc,
unsigned int desiredId);
@ -266,5 +267,5 @@ private:
UPROPERTY(VisibleAnywhere)
AWorldObserver *WorldObserver = nullptr;
crec::Recorder Recorder;
ACarlaRecorder *Recorder = nullptr;
};

View File

@ -0,0 +1,255 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
// #include "Carla.h"
#include "CarlaRecorder.h"
#include <ctime>
#include <sstream>
ACarlaRecorder::ACarlaRecorder(void)
{
PrimaryActorTick.TickGroup = TG_PrePhysics;
Disable();
}
ACarlaRecorder::ACarlaRecorder(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.TickGroup = TG_PrePhysics;
Disable();
}
void ACarlaRecorder::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
// check if recording
if (Enabled && Episode)
{
const FActorRegistry &reg = Episode->GetActorRegistry();
// get positions
for (TActorIterator<ACarlaWheeledVehicle> It(GetWorld()); It; ++It)
{
ACarlaWheeledVehicle *Actor = *It;
check(Actor != nullptr);
CarlaRecorderPosition recPos {
reg.Find(Actor).GetActorId(),
Actor->GetTransform().GetTranslation(),
Actor->GetTransform().GetRotation().Euler()
};
AddPosition(recPos);
}
// get states
for (TActorIterator<ATrafficSignBase> It(GetWorld()); It; ++It)
{
ATrafficSignBase *Actor = *It;
check(Actor != nullptr);
auto TrafficLight = Cast<ATrafficLightBase>(Actor);
if (TrafficLight != nullptr)
{
CarlaRecorderStateTrafficLight recTraffic {
reg.Find(Actor).GetActorId(),
TrafficLight->GetTimeIsFrozen(),
TrafficLight->GetElapsedTime(),
static_cast<char>(TrafficLight->GetTrafficLightState())
};
AddState(recTraffic);
}
}
// write all data for this frame
Write();
}
else if (Episode && Episode->GetReplayer()->IsEnabled())
{
// replayer
Episode->GetReplayer()->Tick(DeltaSeconds);
}
}
void ACarlaRecorder::Enable(void)
{
PrimaryActorTick.bCanEverTick = true;
Enabled = true;
}
void ACarlaRecorder::Disable(void)
{
PrimaryActorTick.bCanEverTick = false;
Enabled = false;
}
std::string ACarlaRecorder::Start(FString Path, FString Name, FString MapName)
{
// reset
Stop();
FString Filename = Path + Name;
// binary file
// file.open(filename.str(), std::ios::binary | std::ios::trunc |
// std::ios::out);
File.open(TCHAR_TO_UTF8(*Filename), std::ios::binary);
if (!File.is_open())
{
// log_error("Recorder file couldn't be created");
return "";
}
// log file
FString LogFilename = Path + Name + ".log";
Log.open(TCHAR_TO_UTF8(*LogFilename));
// save info
Info.Version = 1;
Info.Magic = TEXT("CARLA_RECORDER");
Info.Date = std::time(0);
Info.Mapfile = MapName;
// write general info
Info.Write(File);
Frames.Reset();
Enable();
// add all existing actors
AddExistingActors();
return std::string(TCHAR_TO_UTF8(*Filename));
}
void ACarlaRecorder::Stop(void)
{
Disable();
if (File)
{
File.close();
}
if (Log)
{
Log.close();
}
Clear();
}
void ACarlaRecorder::Clear(void)
{
Events.Clear();
Positions.Clear();
States.Clear();
// log << "Clear\n";
}
void ACarlaRecorder::Write(void)
{
// update this frame data
Frames.SetFrame();
// write data
Frames.Write(File, Log);
Events.Write(File, Log);
Positions.Write(File, Log);
States.Write(File, Log);
Clear();
// log << "Write\n";
}
void ACarlaRecorder::AddPosition(const CarlaRecorderPosition &Position)
{
if (Enabled)
{
Positions.AddPosition(Position);
}
}
void ACarlaRecorder::AddEvent(const CarlaRecorderEventAdd &Event)
{
if (Enabled)
{
Events.AddEvent(std::move(Event));
}
}
void ACarlaRecorder::AddEvent(const CarlaRecorderEventDel &Event)
{
if (Enabled)
{
Events.AddEvent(std::move(Event));
}
}
void ACarlaRecorder::AddEvent(const CarlaRecorderEventParent &Event)
{
if (Enabled)
{
Events.AddEvent(std::move(Event));
}
}
void ACarlaRecorder::AddState(const CarlaRecorderStateTrafficLight &State)
{
if (Enabled)
{
States.AddState(State);
}
}
void ACarlaRecorder::AddExistingActors(void)
{
// registring all existing actors in first frame
FActorRegistry Registry = Episode->GetActorRegistry();
for (auto &&View : Registry)
{
const AActor *Actor = View.GetActor();
if (Actor != nullptr)
{
// create event
CreateRecorderEventAdd(
View.GetActorId(),
Actor->GetActorTransform(),
View.GetActorInfo()->Description);
}
}
}
void ACarlaRecorder::CreateRecorderEventAdd(
unsigned int DatabaseId,
const FTransform &Transform,
FActorDescription ActorDescription)
{
CarlaRecorderActorDescription Description;
Description.UId = ActorDescription.UId;
Description.Id = ActorDescription.Id;
// attributes
Description.Attributes.reserve(ActorDescription.Variations.Num());
for (const auto &item : ActorDescription.Variations)
{
CarlaRecorderActorAttribute Attr;
Attr.Type = static_cast<uint8_t>(item.Value.Type);
Attr.Id = item.Value.Id;
Attr.Value = item.Value.Value;
// check for empty attributes
if (!Attr.Id.IsEmpty())
{
Description.Attributes.emplace_back(std::move(Attr));
}
}
// recorder event
CarlaRecorderEventAdd RecEvent
{
DatabaseId,
Transform.GetTranslation(),
Transform.GetRotation().Euler(),
std::move(Description)
};
AddEvent(std::move(RecEvent));
}

View File

@ -0,0 +1,125 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
// #include "GameFramework/Actor.h"
#include <fstream>
#include "Carla/Game/CarlaRecorderInfo.h"
#include "Carla/Game/CarlaRecorderFrames.h"
#include "Carla/Game/CarlaRecorderEvent.h"
#include "Carla/Game/CarlaRecorderPosition.h"
#include "Carla/Game/CarlaRecorderState.h"
#include "Carla/Game/CarlaReplayer.h"
#include "Carla/Actor/ActorDescription.h"
#include "CarlaRecorder.generated.h"
class AActor;
class UCarlaEpisode;
enum class CarlaRecorderPacketId : uint8_t
{
Frame = 0,
Event,
Position,
State
};
/// Recorder for the simulation
UCLASS()
class CARLA_API ACarlaRecorder : public AActor
{
GENERATED_BODY()
public:
ACarlaRecorder(void);
ACarlaRecorder(const FObjectInitializer &InObjectInitializer);
// enable / disable
bool IsEnabled(void)
{
return Enabled;
}
void Enable(void);
void Disable(void);
// start / stop
std::string Start(FString Path, FString Name, FString MapName);
void Stop(void);
void Clear(void);
void Write(void);
// events
void AddEvent(const CarlaRecorderEventAdd &Event);
void AddEvent(const CarlaRecorderEventDel &Event);
void AddEvent(const CarlaRecorderEventParent &Event);
void AddPosition(const CarlaRecorderPosition &Position);
void AddState(const CarlaRecorderStateTrafficLight &State);
// set episode
void SetEpisode(UCarlaEpisode *ThisEpisode)
{
Episode = ThisEpisode;
}
void CreateRecorderEventAdd(
unsigned int DatabaseId,
const FTransform &Transform,
FActorDescription ActorDescription);
// replayer
CarlaReplayer *GetReplayer(void)
{
return &Replayer;
}
std::string ShowFileInfo(std::string Path, std::string Name)
{
return Replayer.GetInfo(Path + Name);
}
std::string ReplayFile(std::string Path, std::string Name, double TimeStart, double Duration)
{
Stop();
return Replayer.ReplayFile(Path + Name, TimeStart, Duration);
}
// protected:
void Tick(float DeltaSeconds) final;
private:
bool Enabled; // enabled or not
// files
std::ofstream File;
std::ofstream Log;
UCarlaEpisode *Episode = nullptr;
// structures
CarlaRecorderInfo Info;
CarlaRecorderFrames Frames;
CarlaRecorderEvents Events;
CarlaRecorderPositions Positions;
CarlaRecorderStates States;
// replayer
CarlaReplayer Replayer;
void AddExistingActors(void);
};

View File

@ -0,0 +1,184 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "CarlaRecorder.h"
#include "CarlaRecorderEvent.h"
#include "CarlaRecorderHelpers.h"
void CarlaRecorderEventAdd::Write(std::ofstream &OutFile)
{
// OutLog << "add event: " << TCHAR_TO_UTF8(this->Description.Id) << " (id." << this->DatabaseId << ")\n";
// database id
WriteValue<uint32_t>(OutFile, this->DatabaseId);
// transform
WriteFVector(OutFile, this->Location);
WriteFVector(OutFile, this->Rotation);
// description type
WriteValue<uint32_t>(OutFile, this->Description.UId);
WriteFString(OutFile, this->Description.Id);
// attributes
uint16_t Total = this->Description.Attributes.size();
WriteValue<uint16_t>(OutFile, Total);
// OutLog << "Attributes: " << this->description.attributes.size() << std::endl;
for (uint16_t i=0; i<Total; ++i)
{
// type
WriteValue<uint8_t>(OutFile, this->Description.Attributes[i].Type);
WriteFString(OutFile, this->Description.Attributes[i].Id);
WriteFString(OutFile, this->Description.Attributes[i].Value);
// log
// OutLog << " " << TCHAR_TO_UTF8(this->Description.Attributes[i].Id) << " = " << TCHAR_TO_UTF8(this->Description.Attributes[i].Value) << std::endl;
}
}
void CarlaRecorderEventAdd::Read(std::ifstream &InFile)
{
//OutLog << "add event: " << this->description.id.c_str() << " (id." << this->databaseId << ")\n";
// database id
ReadValue<uint32_t>(InFile, this->DatabaseId);
// transform
ReadFVector(InFile, this->Location);
ReadFVector(InFile, this->Rotation);
// description type
ReadValue<uint32_t>(InFile, this->Description.UId);
ReadFString(InFile, this->Description.Id);
// attributes
uint16_t Total;
ReadValue<uint16_t>(InFile, Total);
this->Description.Attributes.clear();
this->Description.Attributes.reserve(Total);
//OutLog << "Attributes: " << this->description.attributes.size() << std::endl;
for (uint16_t i=0; i<Total; ++i)
{
CarlaRecorderActorAttribute Att;
ReadValue<uint8_t>(InFile, Att.Type);
ReadFString(InFile, Att.Id);
ReadFString(InFile, Att.Value);
this->Description.Attributes.push_back(std::move(Att));
// log
//OutLog << " " << att.id.c_str() << " = " << att.value.c_str() << std::endl;
}
}
void CarlaRecorderEventDel::Read(std::ifstream &InFile)
{
// database id
ReadValue<uint32_t>(InFile, this->DatabaseId);
}
void CarlaRecorderEventDel::Write(std::ofstream &OutFile)
{
// database id
WriteValue<uint32_t>(OutFile, this->DatabaseId);
}
void CarlaRecorderEventParent::Read(std::ifstream &InFile)
{
// database id
ReadValue<uint32_t>(InFile, this->DatabaseId);
// database id parent
ReadValue<uint32_t>(InFile, this->DatabaseIdParent);
}
void CarlaRecorderEventParent::Write(std::ofstream &OutFile)
{
// database id
WriteValue<uint32_t>(OutFile, this->DatabaseId);
// database id parent
WriteValue<uint32_t>(OutFile, this->DatabaseIdParent);
}
//---------------------------------------------
void CarlaRecorderEvents::Clear(void)
{
EventsAdd.clear();
EventsDel.clear();
EventsParent.clear();
}
void CarlaRecorderEvents::AddEvent(const CarlaRecorderEventAdd &Event)
{
EventsAdd.push_back(std::move(Event));
}
void CarlaRecorderEvents::AddEvent(const CarlaRecorderEventDel &Event)
{
EventsDel.push_back(std::move(Event));
}
void CarlaRecorderEvents::AddEvent(const CarlaRecorderEventParent &Event)
{
EventsParent.push_back(std::move(Event));
}
void CarlaRecorderEvents::WriteEventsAdd(std::ofstream &OutFile)
{
// write total records
uint16_t Total = EventsAdd.size();
WriteValue<uint16_t>(OutFile, Total);
for (uint16_t i=0; i<Total; ++i)
EventsAdd[i].Write(OutFile);
}
void CarlaRecorderEvents::WriteEventsDel(std::ofstream &OutFile, std::ofstream &OutLog)
{
// write total records
uint16_t Total = EventsDel.size();
WriteValue<uint16_t>(OutFile, Total);
for (uint16_t i=0; i<Total; ++i)
{
OutLog << "add del: " << EventsDel[i].DatabaseId << "\n";
EventsDel[i].Write(OutFile);
}
}
void CarlaRecorderEvents::WriteEventsParent(std::ofstream &OutFile, std::ofstream &OutLog)
{
// write total records
uint16_t Total = EventsParent.size();
WriteValue<uint16_t>(OutFile, Total);
for (uint16_t i=0; i<Total; ++i)
{
OutLog << "add parent: id." << EventsParent[i].DatabaseId << ", parent." << EventsParent[i].DatabaseIdParent << "\n";
EventsParent[i].Write(OutFile);
}
}
void CarlaRecorderEvents::Write(std::ofstream &OutFile, std::ofstream &OutLog)
{
// write the packet id
WriteValue<char>(OutFile, static_cast<char>(CarlaRecorderPacketId::Event));
std::streampos PosStart = OutFile.tellp();
// write a dummy packet size
uint32_t Total = 0;
WriteValue<uint32_t>(OutFile, Total);
// write events
WriteEventsAdd(OutFile);
WriteEventsDel(OutFile, OutLog);
WriteEventsParent(OutFile, OutLog);
// write the real packet size
std::streampos PosEnd = OutFile.tellp();
Total = PosEnd - PosStart - sizeof(uint32_t);
OutFile.seekp(PosStart, std::ios::beg);
WriteValue<uint32_t>(OutFile, Total);
OutFile.seekp(PosEnd, std::ios::beg);
OutLog << "write events (" << EventsAdd.size() << "," << EventsDel.size() << "," << EventsParent.size() << ")\n";
}

View File

@ -0,0 +1,71 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include <vector>
struct CarlaRecorderActorAttribute
{
uint8_t Type; // EActorAttributeType
FString Id; // string
FString Value; // string
};
struct CarlaRecorderActorDescription
{
uint32_t UId;
FString Id; // string
std::vector<CarlaRecorderActorAttribute> Attributes;
};
struct CarlaRecorderEventAdd
{
uint32_t DatabaseId;
FVector Location;
FVector Rotation;
CarlaRecorderActorDescription Description;
void Read(std::ifstream &InFile);
void Write(std::ofstream &OutFile);
};
struct CarlaRecorderEventDel
{
uint32_t DatabaseId;
void Read(std::ifstream &InFile);
void Write(std::ofstream &OutFile);
};
struct CarlaRecorderEventParent
{
uint32_t DatabaseId;
uint32_t DatabaseIdParent;
void Read(std::ifstream &InFile);
void Write(std::ofstream &OutFile);
};
class CarlaRecorderEvents {
public:
void AddEvent(const CarlaRecorderEventAdd &Event);
void AddEvent(const CarlaRecorderEventDel &Event);
void AddEvent(const CarlaRecorderEventParent &Event);
void Clear(void);
void Write(std::ofstream &OutFile, std::ofstream &OutLog);
private:
std::vector<CarlaRecorderEventAdd> EventsAdd;
std::vector<CarlaRecorderEventDel> EventsDel;
std::vector<CarlaRecorderEventParent> EventsParent;
void WriteEventsAdd(std::ofstream &OutFile);
void WriteEventsDel(std::ofstream &OutFile, std::ofstream &OutLog);
void WriteEventsParent(std::ofstream &OutFile, std::ofstream &OutLog);
};

View File

@ -0,0 +1,87 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "CarlaRecorder.h"
#include "CarlaRecorderFrames.h"
#include "CarlaRecorderHelpers.h"
void CarlaRecorderFrame::Read(std::ifstream &InFile)
{
ReadValue<CarlaRecorderFrame>(InFile, *this);
}
void CarlaRecorderFrame::Write(std::ofstream &OutFile)
{
WriteValue<CarlaRecorderFrame>(OutFile, *this);
}
// ---------------------------------------------
CarlaRecorderFrames::CarlaRecorderFrames(void)
{
Reset();
}
void CarlaRecorderFrames::Reset(void)
{
Frame.Id = 0;
Frame.DurationThis = 0.0f;
Frame.Elapsed = 0.0f;
LastTime = std::chrono::high_resolution_clock::now();
OffsetPreviousFrame = 0;
}
void CarlaRecorderFrames::SetFrame(void)
{
auto Now = std::chrono::high_resolution_clock::now();
if (Frame.Id == 0)
{
Frame.Elapsed = 0.0f;
Frame.DurationThis = 0.0f;
}
else
{
Frame.DurationThis = std::chrono::duration<double>(Now - LastTime).count();
Frame.Elapsed += Frame.DurationThis;
}
LastTime = Now;
++Frame.Id;
}
void CarlaRecorderFrames::Write(std::ofstream &OutFile, std::ofstream &OutLog)
{
std::streampos Pos, Offset;
double Dummy = -1.0f;
// write the packet id
WriteValue<char>(OutFile, static_cast<char>(CarlaRecorderPacketId::Frame));
// write the packet size
uint32_t Total = sizeof(CarlaRecorderFrame);
WriteValue<uint32_t>(OutFile, Total);
// write frame record
WriteValue<uint64_t>(OutFile, Frame.Id);
Offset = OutFile.tellp();
WriteValue<double>(OutFile, Dummy);
WriteValue<double>(OutFile, Frame.Elapsed);
// we need to write this duration to previous frame
if (OffsetPreviousFrame > 0)
{
Pos = OutFile.tellp();
OutFile.seekp(OffsetPreviousFrame, std::ios::beg);
WriteValue<double>(OutFile, Frame.DurationThis);
OutFile.seekp(Pos, std::ios::beg);
}
// save position for next actualization
OffsetPreviousFrame = Offset;
OutLog << "frame " << Frame.Id << " elapsed " << Frame.Elapsed << "\n";
}

View File

@ -0,0 +1,43 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include <chrono>
#pragma pack(push, 1)
struct CarlaRecorderFrame
{
uint64_t Id;
double DurationThis;
double Elapsed;
void Read(std::ifstream &InFile);
void Write(std::ofstream &OutFile);
};
#pragma pack(pop)
class CarlaRecorderFrames
{
public:
CarlaRecorderFrames(void);
void Reset();
void SetFrame(void);
void Write(std::ofstream &OutFile, std::ofstream &OutLog);
private:
CarlaRecorderFrame Frame;
std::streampos OffsetPreviousFrame;
std::chrono::time_point<std::chrono::high_resolution_clock> LastTime;
};

View File

@ -0,0 +1,87 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include <vector>
#include "UnrealString.h"
#include "CarlaRecorderHelpers.h"
// create a temporal buffer to convert from and to FString and bytes
static std::vector<uint8_t> CarlaRecorderHelperBuffer;
// ------
// write
// ------
// write binary data from FVector
void WriteFVector(std::ofstream &OutFile, const FVector &InObj)
{
WriteValue<float>(OutFile, InObj.X);
WriteValue<float>(OutFile, InObj.Y);
WriteValue<float>(OutFile, InObj.Z);
}
// write binary data from FTransform
// void WriteFTransform(std::ofstream &OutFile, const FTransform &InObj){
// WriteFVector(OutFile, InObj.GetTranslation());
// WriteFVector(OutFile, InObj.GetRotation().Euler());
// }
// write binary data from FString (length + text)
void WriteFString(std::ofstream &OutFile, const FString &InObj)
{
// encode the string to UTF8 to know the final length
FTCHARToUTF8 EncodedString(*InObj);
int16_t Length = EncodedString.Length();
// write
WriteValue<uint16_t>(OutFile, Length);
OutFile.write(reinterpret_cast<char *>(TCHAR_TO_UTF8(*InObj)), Length);
}
// -----
// read
// -----
// read binary data to FVector
void ReadFVector(std::ifstream &InFile, FVector &OutObj)
{
ReadValue<float>(InFile, OutObj.X);
ReadValue<float>(InFile, OutObj.Y);
ReadValue<float>(InFile, OutObj.Z);
}
// read binary data to FTransform
// void ReadFTransform(std::ifstream &InFile, FTransform &OutObj){
// FVector Vec;
// ReadFVector(InFile, Vec);
// OutObj.SetTranslation(Vec);
// ReadFVector(InFile, Vec);
// OutObj.GetRotation().MakeFromEuler(Vec);
// }
// read binary data to FString (length + text)
void ReadFString(std::ifstream &InFile, FString &OutObj)
{
uint16_t Length;
ReadValue<uint16_t>(InFile, Length);
// make room in vector buffer
if (CarlaRecorderHelperBuffer.capacity() < Length + 1)
{
CarlaRecorderHelperBuffer.reserve(Length + 1);
}
CarlaRecorderHelperBuffer.clear();
// initialize the vector space with 0
CarlaRecorderHelperBuffer.resize(Length + 1);
// CarlaRecorderHelperBuffer.push_back(0);
// read
InFile.read(reinterpret_cast<char *>(CarlaRecorderHelperBuffer.data()), Length);
// convert from UTF8 to FString
// OutObj = BytesToString(reinterpret_cast<uint8_t
// *>(UTF8_TO_TCHAR(CarlaRecorderHelperBuffer.data())), Length);
// OutObj = BytesToString(reinterpret_cast<uint8_t
// *>(CarlaRecorderHelperBuffer.data()), Length);
OutObj = FString(UTF8_TO_TCHAR(CarlaRecorderHelperBuffer.data()));
}

View File

@ -0,0 +1,47 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
// ---------
// recorder
// ---------
// write binary data (using sizeof())
template <typename T>
void WriteValue(std::ofstream &OutFile, const T &InObj)
{
OutFile.write(reinterpret_cast<const char *>(&InObj), sizeof(T));
}
// write binary data from FVector
void WriteFVector(std::ofstream &OutFile, const FVector &InObj);
// write binary data from FTransform
// void WriteFTransform(std::ofstream &OutFile, const FTransform &InObj);
// write binary data from FString (length + text)
void WriteFString(std::ofstream &OutFile, const FString &InObj);
// ---------
// replayer
// ---------
// read binary data (using sizeof())
template <typename T>
void ReadValue(std::ifstream &InFile, T &OutObj)
{
InFile.read(reinterpret_cast<char *>(&OutObj), sizeof(T));
}
// read binary data from FVector
void ReadFVector(std::ifstream &InFile, FVector &OutObj);
// read binary data from FTransform
// void ReadTransform(std::ifstream &InFile, FTransform &OutObj);
// read binary data from FString (length + text)
void ReadFString(std::ifstream &InFile, FString &OutObj);

View File

@ -0,0 +1,36 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CarlaRecorderHelpers.h"
#include <fstream>
#include <ctime>
struct CarlaRecorderInfo
{
uint16_t Version;
FString Magic;
std::time_t Date;
FString Mapfile;
void Read(std::ifstream &File)
{
ReadValue<uint16_t>(File, Version);
ReadFString(File, Magic);
ReadValue<std::time_t>(File, Date);
ReadFString(File, Mapfile);
}
void Write(std::ofstream &File)
{
WriteValue<uint16_t>(File, Version);
WriteFString(File, Magic);
WriteValue<std::time_t>(File, Date);
WriteFString(File, Mapfile);
}
};

View File

@ -0,0 +1,61 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "CarlaRecorder.h"
#include "CarlaRecorderPosition.h"
#include "CarlaRecorderHelpers.h"
void CarlaRecorderPosition::Write(std::ofstream &OutFile)
{
// database id
WriteValue<uint32_t>(OutFile, this->DatabaseId);
// transform
WriteFVector(OutFile, this->Location);
WriteFVector(OutFile, this->Rotation);
}
void CarlaRecorderPosition::Read(std::ifstream &InFile)
{
// database id
ReadValue<uint32_t>(InFile, this->DatabaseId);
// transform
ReadFVector(InFile, this->Location);
ReadFVector(InFile, this->Rotation);
}
// ---------------------------------------------
void CarlaRecorderPositions::Clear(void)
{
Positions.clear();
}
void CarlaRecorderPositions::AddPosition(const CarlaRecorderPosition &Position)
{
Positions.push_back(Position);
}
void CarlaRecorderPositions::Write(std::ofstream &OutFile, std::ofstream &OutLog)
{
// write the packet id
WriteValue<char>(OutFile, static_cast<char>(CarlaRecorderPacketId::Position));
// write the packet size
uint32_t Total = 2 + Positions.size() * sizeof(CarlaRecorderPosition);
WriteValue<uint32_t>(OutFile, Total);
// write total records
Total = Positions.size();
WriteValue<uint16_t>(OutFile, Total);
// write records
if (Total > 0)
{
OutFile.write(reinterpret_cast<const char *>(Positions.data()),
Positions.size() * sizeof(CarlaRecorderPosition));
}
OutLog << "write positions (" << Positions.size() << " * " << sizeof(CarlaRecorderPosition) << ")\n";
}

View File

@ -0,0 +1,41 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include <vector>
#pragma pack(push, 1)
struct CarlaRecorderPosition
{
uint32_t DatabaseId;
FVector Location;
FVector Rotation;
// FVector Velocity;
// FVector AngularVelocity;
void Read(std::ifstream &InFile);
void Write(std::ofstream &OutFile);
};
#pragma pack(pop)
class CarlaRecorderPositions
{
public:
void AddPosition(const CarlaRecorderPosition &InObj);
void Clear(void);
void Write(std::ofstream &OutFile, std::ofstream &OutLog);
private:
std::vector<CarlaRecorderPosition> Positions;
};

View File

@ -0,0 +1,64 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "CarlaRecorder.h"
#include "CarlaRecorderState.h"
#include "CarlaRecorderHelpers.h"
void CarlaRecorderStateTrafficLight::Write(std::ofstream &OutFile)
{
WriteValue<uint32_t>(OutFile, this->DatabaseId);
WriteValue<bool>(OutFile, this->IsFrozen);
WriteValue<float>(OutFile, this->ElapsedTime);
WriteValue<char>(OutFile, this->State);
}
void CarlaRecorderStateTrafficLight::Read(std::ifstream &InFile)
{
ReadValue<uint32_t>(InFile, this->DatabaseId);
ReadValue<bool>(InFile, this->IsFrozen);
ReadValue<float>(InFile, this->ElapsedTime);
ReadValue<char>(InFile, this->State);
}
// ---------------------------------------------
void CarlaRecorderStates::Clear(void)
{
StatesTrafficLights.clear();
}
void CarlaRecorderStates::AddState(const CarlaRecorderStateTrafficLight &State)
{
StatesTrafficLights.push_back(std::move(State));
}
void CarlaRecorderStates::WriteStatesTrafficLight(std::ofstream &OutFile)
{
// write total records
uint16_t Total = StatesTrafficLights.size();
WriteValue<uint16_t>(OutFile, Total);
for (uint16_t i = 0; i < Total; ++i)
{
StatesTrafficLights[i].Write(OutFile);
}
}
void CarlaRecorderStates::Write(std::ofstream &OutFile, std::ofstream &OutLog)
{
// write the packet id
WriteValue<char>(OutFile, static_cast<char>(CarlaRecorderPacketId::State));
// write the packet size
uint32_t Total = 2 + StatesTrafficLights.size() * sizeof(CarlaRecorderStateTrafficLight);
WriteValue<uint32_t>(OutFile, Total);
// write events
WriteStatesTrafficLight(OutFile);
OutLog << "write states (" << StatesTrafficLights.size() << ")\n";
}

View File

@ -0,0 +1,45 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#pragma pack(push, 1)
struct CarlaRecorderStateTrafficLight
{
uint32_t DatabaseId;
bool IsFrozen;
float ElapsedTime;
char State;
void Read(std::ifstream &InFile);
void Write(std::ofstream &OutFile);
};
#pragma pack(pop)
class CarlaRecorderStates
{
public:
void AddState(const CarlaRecorderStateTrafficLight &State);
void Clear(void);
void Write(std::ofstream &OutFile, std::ofstream &OutLog);
private:
std::vector<CarlaRecorderStateTrafficLight> StatesTrafficLights;
void WriteStatesTrafficLight(std::ofstream &OutFile);
};

View File

@ -0,0 +1,683 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "CarlaReplayer.h"
#include "CarlaRecorder.h"
#include <ctime>
#include <sstream>
CarlaReplayer::CarlaReplayer()
{}
CarlaReplayer::~CarlaReplayer()
{
Stop();
}
// callbacks
void CarlaReplayer::SetCallbackEventAdd(CarlaRecorderCallbackEventAdd f)
{
CallbackEventAdd = std::move(f);
}
void CarlaReplayer::SetCallbackEventDel(CarlaRecorderCallbackEventDel f)
{
CallbackEventDel = std::move(f);
}
void CarlaReplayer::SetCallbackEventParent(CarlaRecorderCallbackEventParent f)
{
CallbackEventParent = std::move(f);
}
void CarlaReplayer::SetCallbackEventPosition(CarlaRecorderCallbackPosition f)
{
CallbackPosition = std::move(f);
}
void CarlaReplayer::SetCallbackEventFinish(CarlaRecorderCallbackFinish f)
{
CallbackFinish = std::move(f);
}
void CarlaReplayer::SetCallbackStateTrafficLight(CarlaRecorderCallbackStateTrafficLight f)
{
CallbackStateTrafficLight = std::move(f);
}
void CarlaReplayer::Stop(bool KeepActors)
{
if (Enabled)
{
Enabled = false;
// destroy actors if event was recorded?
if (!KeepActors)
{
ProcessToTime(TotalTime);
}
File.close();
// callback
if (CallbackFinish)
{
CallbackFinish(KeepActors);
}
}
// if (!KeepActors)
// UE_LOG(LogCarla, Log, TEXT("Replayer stop"));
// else
// UE_LOG(LogCarla, Log, TEXT("Replayer stop (keeping actors)"));
}
bool CarlaReplayer::ReadHeader()
{
if (File.eof())
{
return false;
}
ReadValue<char>(File, Header.Id);
ReadValue<uint32_t>(File, Header.Size);
return true;
}
void CarlaReplayer::SkipPacket(void)
{
File.seekg(Header.Size, std::ios::cur);
}
std::string CarlaReplayer::GetInfo(std::string Filename)
{
std::stringstream Info;
// try to open
File.open(Filename, std::ios::binary);
if (!File.is_open())
{
Info << "File " << Filename << " not found on server\n";
return Info.str();
}
uint16_t i, Total;
CarlaRecorderEventAdd EventAdd;
CarlaRecorderEventDel EventDel;
CarlaRecorderEventParent EventParent;
// CarlaRecorderStateTrafficLight StateTraffic;
bool bShowFrame;
// read Info
RecInfo.Read(File);
// check magic string
// Info << "Checking Magic: " << TCHAR_TO_UTF8(*RecInfo.Magic) << std::endl;
if (RecInfo.Magic != "CARLA_RECORDER")
{
Info << "File is not a CARLA recorder" << std::endl;
return Info.str();
}
// show general Info
Info << "Version: " << RecInfo.Version << std::endl;
Info << "Map: " << TCHAR_TO_UTF8(*RecInfo.Mapfile) << std::endl;
tm *TimeInfo = localtime(&RecInfo.Date);
char DateStr[100];
strftime(DateStr, 100, "%x %X", TimeInfo);
Info << "Date: " << DateStr << std::endl << std::endl;
// parse only frames
while (File)
{
// get header
if (!ReadHeader())
{
break;
}
// check for a frame packet
switch (Header.Id)
{
case static_cast<char>(CarlaRecorderPacketId::Frame):
Frame.Read(File);
// Info << "Frame " << Frame.Id << " at " << Frame.Elapsed << " seconds
// (offset 0x" << std::hex << File.tellg() << std::dec << ")\n";
break;
case static_cast<char>(CarlaRecorderPacketId::Event):
bShowFrame = true;
ReadValue<uint16_t>(File, Total);
if (Total > 0 && bShowFrame)
{
Info << "Frame " << Frame.Id << " at " << Frame.Elapsed << " seconds\n";
bShowFrame = false;
}
for (i = 0; i < Total; ++i)
{
// add
EventAdd.Read(File);
Info << " Create " << EventAdd.DatabaseId << ": " << TCHAR_TO_UTF8(*EventAdd.Description.Id) <<
" (" <<
EventAdd.Description.UId << ") at (" << EventAdd.Location.X << ", " <<
EventAdd.Location.Y << ", " << EventAdd.Location.Z << ")" << std::endl;
for (auto &Att : EventAdd.Description.Attributes)
{
Info << " " << TCHAR_TO_UTF8(*Att.Id) << " = " << TCHAR_TO_UTF8(*Att.Value) << std::endl;
}
}
// del
ReadValue<uint16_t>(File, Total);
if (Total > 0 && bShowFrame)
{
Info << "Frame " << Frame.Id << " at " << Frame.Elapsed << " seconds\n";
bShowFrame = false;
}
for (i = 0; i < Total; ++i)
{
EventDel.Read(File);
Info << " Destroy " << EventDel.DatabaseId << "\n";
}
// parenting
ReadValue<uint16_t>(File, Total);
if (Total > 0 && bShowFrame)
{
Info << "Frame " << Frame.Id << " at " << Frame.Elapsed << " seconds\n";
bShowFrame = false;
}
for (i = 0; i < Total; ++i)
{
EventParent.Read(File);
Info << " Parenting " << EventParent.DatabaseId << " with " << EventDel.DatabaseId <<
" (parent)\n";
}
break;
case static_cast<char>(CarlaRecorderPacketId::Position):
// Info << "Positions\n";
SkipPacket();
break;
case static_cast<char>(CarlaRecorderPacketId::State):
SkipPacket();
// bShowFrame = true;
// readValue<uint16_t>(File, Total);
// if (Total > 0 && bShowFrame) {
// Info << "Frame " << frame.id << " at " << frame.Elapsed << "
// seconds\n";
// bShowFrame = false;
// }
// Info << " State traffic lights: " << Total << std::endl;
// for (i = 0; i < Total; ++i) {
// stateTraffic.read(File);
// Info << " Id: " << stateTraffic.DatabaseId << " state: " <<
// static_cast<char>(0x30 + stateTraffic.state) << " frozen: " <<
// stateTraffic.isFrozen << " elapsedTime: " << stateTraffic.elapsedTime
// << std::endl;
// }
break;
default:
// skip packet
Info << "Unknown packet id: " << Header.Id << " at offset " << File.tellg() << std::endl;
SkipPacket();
break;
}
}
Info << "\nFrames: " << Frame.Id << "\n";
Info << "Duration: " << Frame.Elapsed << " seconds\n";
File.close();
return Info.str();
}
void CarlaReplayer::Rewind(void)
{
CurrentTime = 0.0f;
TotalTime = 0.0f;
TimeToStop = 0.0f;
File.clear();
File.seekg(0, std::ios::beg);
// mark as header as invalid to force reload a new one next time
Frame.Elapsed = -1.0f;
Frame.DurationThis = 0.0f;
MappedId.clear();
// read geneal Info
RecInfo.Read(File);
// UE_LOG(LogCarla, Log, TEXT("Replayer rewind"));
}
// read last frame in File and return the Total time recorded
double CarlaReplayer::GetTotalTime(void)
{
std::streampos Current = File.tellg();
// parse only frames
while (File)
{
// get header
if (!ReadHeader())
{
break;
}
// check for a frame packet
switch (Header.Id)
{
case static_cast<char>(CarlaRecorderPacketId::Frame):
Frame.Read(File);
break;
default:
SkipPacket();
break;
}
}
File.clear();
File.seekg(Current, std::ios::beg);
return Frame.Elapsed;
}
std::string CarlaReplayer::ReplayFile(std::string Filename, double TimeStart, double Duration)
{
std::stringstream Info;
std::string s;
// check to stop if we are replaying another
if (Enabled)
{
Stop();
}
Info << "Replaying File: " << Filename << std::endl;
// try to open
File.open(Filename, std::ios::binary);
if (!File.is_open())
{
Info << "File " << Filename << " not found on server\n";
return Info.str();
}
// from start
Rewind();
// get Total time of recorder
TotalTime = GetTotalTime();
Info << "Total time recorded: " << TotalTime << std::endl;
// set time to start replayer
if (TimeStart < 0.0f)
{
TimeStart = TotalTime + TimeStart;
if (TimeStart < 0.0f)
{
TimeStart = 0.0f;
}
}
// set time to stop replayer
if (Duration > 0.0f)
{
TimeToStop = TimeStart + Duration;
}
else
{
TimeToStop = TotalTime;
}
Info << "Replaying from " << TimeStart << " s - " << TimeToStop << " s (" << TotalTime << " s)" <<
std::endl;
// process all events until the time
ProcessToTime(TimeStart);
// mark as enabled
Enabled = true;
return Info.str();
}
void CarlaReplayer::ProcessToTime(double Time)
{
double Per = 0.0f;
double NewTime = CurrentTime + Time;
bool bFrameFound = false;
// check if we are in the right frame
if (NewTime >= Frame.Elapsed && NewTime < Frame.Elapsed + Frame.DurationThis)
{
Per = (NewTime - Frame.Elapsed) / Frame.DurationThis;
bFrameFound = true;
}
// process all frames until time we want or end
while (!File.eof() && !bFrameFound)
{
// get header
ReadHeader();
// check it is a frame packet
if (Header.Id != static_cast<char>(CarlaRecorderPacketId::Frame))
{
if (!File.eof())
{
UE_LOG(LogCarla, Log, TEXT("Replayer File error: waitting for a Frame packet"));
}
Stop();
break;
}
// read current frame
Frame.Read(File);
// check if target time is in this frame
if (Frame.Elapsed + Frame.DurationThis < NewTime)
{
Per = 0.0f;
}
else
{
Per = (NewTime - Frame.Elapsed) / Frame.DurationThis;
bFrameFound = true;
}
// Info << "Frame: " << Frame.id << " (" << Frame.DurationThis << " / " <<
// Frame.Elapsed << ") per: " << Per << std::endl;
// get header
ReadHeader();
// check it is an events packet
if (Header.Id != static_cast<char>(CarlaRecorderPacketId::Event))
{
UE_LOG(LogCarla, Log, TEXT("Replayer File error: waitting for an Event packet"));
Stop();
break;
}
ProcessEvents();
// get header
ReadHeader();
// check it is a positions packet
if (Header.Id != static_cast<char>(CarlaRecorderPacketId::Position))
{
UE_LOG(LogCarla, Log, TEXT("Replayer File error: waitting for a Position packet"));
Stop();
break;
}
if (bFrameFound)
{
ProcessPositions();
}
else
{
SkipPacket();
}
// get header
ReadHeader();
// check it is an state packet
if (Header.Id != static_cast<char>(CarlaRecorderPacketId::State))
{
UE_LOG(LogCarla, Log, TEXT("Replayer File error: waitting for an State packet"));
Stop();
break;
}
if (bFrameFound)
{
ProcessStates();
}
else
{
SkipPacket();
}
// UE_LOG(LogCarla, Log, TEXT("Replayer new frame"));
}
// update all positions
if (Enabled && bFrameFound)
{
UpdatePositions(Per);
}
// save current time
CurrentTime = NewTime;
// stop replay?
if (CurrentTime >= TimeToStop)
{
// check if we need to stop the replayer and let it continue in simulation
// mode
if (TimeToStop == TotalTime)
{
Stop();
}
else
{
Stop(true); // keep actors in scene so they continue with AI
}
}
}
void CarlaReplayer::ProcessEvents(void)
{
uint16_t i, Total;
CarlaRecorderEventAdd EventAdd;
CarlaRecorderEventDel EventDel;
CarlaRecorderEventParent EventParent;
std::stringstream Info;
// create events
ReadValue<uint16_t>(File, Total);
for (i = 0; i < Total; ++i)
{
EventAdd.Read(File);
// avoid sensor events
if (!EventAdd.Description.Id.StartsWith("sensor."))
{
// show log
Info.str("");
Info << " Create " << EventAdd.DatabaseId << ": " << TCHAR_TO_UTF8(*EventAdd.Description.Id) << " (" <<
EventAdd.Description.UId << ") at (" << EventAdd.Location.X << ", " <<
EventAdd.Location.Y << ", " << EventAdd.Location.Z << ")" << std::endl;
for (auto &Att : EventAdd.Description.Attributes)
{
Info << " " << TCHAR_TO_UTF8(*Att.Id) << " = " << TCHAR_TO_UTF8(*Att.Value) << std::endl;
}
// UE_LOG(LogCarla, Log, "%s", Info.str().c_str());
// callback
if (CallbackEventAdd)
{
// UE_LOG(LogCarla, Log, TEXT("calling callback add"));
auto Result = CallbackEventAdd(
EventAdd.Location,
EventAdd.Rotation,
std::move(EventAdd.Description),
EventAdd.DatabaseId);
switch (Result.first)
{
case 0:
UE_LOG(LogCarla, Log, TEXT("actor could not be created"));
break;
case 1:
if (Result.second != EventAdd.DatabaseId)
{
UE_LOG(LogCarla, Log, TEXT("actor created but with different id"));
}
// mapping id (recorded Id is a new Id in replayer)
MappedId[EventAdd.DatabaseId] = Result.second;
break;
case 2:
UE_LOG(LogCarla, Log, TEXT("actor already exist, not created"));
// mapping id (say desired Id is mapped to what)
MappedId[EventAdd.DatabaseId] = Result.second;
break;
}
}
else
{
UE_LOG(LogCarla, Log, TEXT("callback add is not defined"));
}
}
}
// destroy events
ReadValue<uint16_t>(File, Total);
for (i = 0; i < Total; ++i)
{
EventDel.Read(File);
Info.str("");
Info << "Destroy " << MappedId[EventDel.DatabaseId] << "\n";
// UE_LOG(LogCarla, Log, "%s", Info.str().c_str());
// callback
if (CallbackEventDel)
{
CallbackEventDel(MappedId[EventDel.DatabaseId]);
MappedId.erase(EventDel.DatabaseId);
}
else
{
UE_LOG(LogCarla, Log, TEXT("callback del is not defined"));
}
}
// parenting events
ReadValue<uint16_t>(File, Total);
for (i = 0; i < Total; ++i)
{
EventParent.Read(File);
Info.str("");
Info << "Parenting " << MappedId[EventParent.DatabaseId] << " with " << MappedId[EventDel.DatabaseId] <<
" (parent)\n";
// UE_LOG(LogCarla, Log, "%s", Info.str().c_str());
// callback
if (CallbackEventParent)
{
CallbackEventParent(MappedId[EventParent.DatabaseId], MappedId[EventParent.DatabaseIdParent]);
}
else
{
UE_LOG(LogCarla, Log, TEXT("callback parent is not defined"));
}
}
}
void CarlaReplayer::ProcessStates(void)
{
uint16_t i, Total;
CarlaRecorderStateTrafficLight StateTrafficLight;
std::stringstream Info;
// read Total traffic light states
ReadValue<uint16_t>(File, Total);
for (i = 0; i < Total; ++i)
{
StateTrafficLight.Read(File);
// callback
if (CallbackStateTrafficLight)
{
// UE_LOG(LogCarla, Log, TEXT("calling callback add"));
StateTrafficLight.DatabaseId = MappedId[StateTrafficLight.DatabaseId];
if (!CallbackStateTrafficLight(StateTrafficLight))
{
UE_LOG(LogCarla,
Log,
TEXT("callback state traffic light %d called but didn't work"),
StateTrafficLight.DatabaseId);
}
}
else
{
UE_LOG(LogCarla, Log, TEXT("callback state traffic light is not defined"));
}
}
}
void CarlaReplayer::ProcessPositions(void)
{
uint16_t i, Total;
// save current as previous
PrevPos = std::move(CurrPos);
// read all positions
ReadValue<uint16_t>(File, Total);
CurrPos.clear();
CurrPos.reserve(Total);
for (i = 0; i < Total; ++i)
{
CarlaRecorderPosition Pos;
Pos.Read(File);
// assign mapped Id
auto NewId = MappedId.find(Pos.DatabaseId);
if (NewId != MappedId.end())
{
Pos.DatabaseId = NewId->second;
}
CurrPos.push_back(std::move(Pos));
}
}
void CarlaReplayer::UpdatePositions(double Per)
{
unsigned int i;
std::unordered_map<int, int> TempMap;
// map the id of all previous positions to its index
for (i = 0; i < PrevPos.size(); ++i)
{
TempMap[PrevPos[i].DatabaseId] = i;
}
// go through each actor and update
for (i = 0; i < CurrPos.size(); ++i)
{
// check if exist a previous position
auto Result = TempMap.find(CurrPos[i].DatabaseId);
if (Result != TempMap.end())
{
// interpolate
InterpolatePosition(PrevPos[Result->second], CurrPos[i], Per);
}
else
{
// assign last position (we don't have previous one)
InterpolatePosition(CurrPos[i], CurrPos[i], 0);
// UE_LOG(LogCarla, Log, TEXT("Interpolation not possible, only one
// position"));
}
}
}
// interpolate a position (transform, velocity...)
void CarlaReplayer::InterpolatePosition(
const CarlaRecorderPosition &Pos1,
const CarlaRecorderPosition &Pos2,
double Per)
{
// call the callback
if (CallbackPosition)
{
CallbackPosition(Pos1, Pos2, Per);
}
}
// tick for the replayer
void CarlaReplayer::Tick(float Delta)
{
// check if there are events to process
if (Enabled)
{
ProcessToTime(Delta);
}
// UE_LOG(LogCarla, Log, TEXT("Replayer tick"));
}

View File

@ -0,0 +1,126 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <functional>
#include "CarlaRecorderInfo.h"
#include "CarlaRecorderFrames.h"
#include "CarlaRecorderEvent.h"
#include "CarlaRecorderPosition.h"
#include "CarlaRecorderState.h"
#include "CarlaRecorderHelpers.h"
// callback prototypes
typedef std::function<std::pair<int, uint32_t>(FVector Location, FVector Rotation,
CarlaRecorderActorDescription Desc, uint32_t UId)> CarlaRecorderCallbackEventAdd;
typedef std::function<bool (uint32_t UId)> CarlaRecorderCallbackEventDel;
typedef std::function<bool (uint32_t ChildId, uint32_t ParentId)> CarlaRecorderCallbackEventParent;
typedef std::function<bool (CarlaRecorderPosition Pos1, CarlaRecorderPosition Pos2,
double Per)> CarlaRecorderCallbackPosition;
typedef std::function<bool (bool ApplyAutopilot)> CarlaRecorderCallbackFinish;
typedef std::function<bool (CarlaRecorderStateTrafficLight State)> CarlaRecorderCallbackStateTrafficLight;
#pragma pack(push, 1)
struct OHeader
{
char Id;
uint32_t Size;
};
#pragma pack(pop)
class CarlaReplayer
{
public:
CarlaReplayer();
~CarlaReplayer();
std::string GetInfo(std::string Filename);
std::string ReplayFile(std::string Filename, double TimeStart = 0.0f, double Duration = 0.0f);
// void Start(void);
void Stop(bool KeepActors = false);
void Enable(void);
void Disable(void);
bool IsEnabled(void)
{
return Enabled;
}
// callbacks
void SetCallbackEventAdd(CarlaRecorderCallbackEventAdd f);
void SetCallbackEventDel(CarlaRecorderCallbackEventDel f);
void SetCallbackEventParent(CarlaRecorderCallbackEventParent f);
void SetCallbackEventPosition(CarlaRecorderCallbackPosition f);
void SetCallbackEventFinish(CarlaRecorderCallbackFinish f);
void SetCallbackStateTrafficLight(CarlaRecorderCallbackStateTrafficLight f);
// tick for the replayer
void Tick(float Time);
private:
bool Enabled;
// binary file reader
std::ifstream File;
OHeader Header;
CarlaRecorderInfo RecInfo;
CarlaRecorderFrame Frame;
// callbacks
CarlaRecorderCallbackEventAdd CallbackEventAdd;
CarlaRecorderCallbackEventDel CallbackEventDel;
CarlaRecorderCallbackEventParent CallbackEventParent;
CarlaRecorderCallbackPosition CallbackPosition;
CarlaRecorderCallbackFinish CallbackFinish;
CarlaRecorderCallbackStateTrafficLight CallbackStateTrafficLight;
// positions (to be able to interpolate)
std::vector<CarlaRecorderPosition> CurrPos;
std::vector<CarlaRecorderPosition> PrevPos;
// mapping id
std::unordered_map<uint32_t, uint32_t> MappedId;
// times
double CurrentTime;
double TimeToStop;
double TotalTime;
// utils
bool ReadHeader();
void SkipPacket();
double GetTotalTime(void);
void Rewind(void);
// processing packets
void ProcessToTime(double Time);
void ProcessEvents(void);
void ProcessPositions(void);
void ProcessStates(void);
// positions
void UpdatePositions(double Per);
void InterpolatePosition(const CarlaRecorderPosition &Start, const CarlaRecorderPosition &End, double Per);
};

View File

@ -16,6 +16,8 @@ ATheNewCarlaGameModeBase::ATheNewCarlaGameModeBase(const FObjectInitializer& Obj
Episode = CreateDefaultSubobject<UCarlaEpisode>(TEXT("Episode"));
Recorder = CreateDefaultSubobject<ACarlaRecorder>(TEXT("Recorder"));
TaggerDelegate = CreateDefaultSubobject<UTaggerDelegate>(TEXT("TaggerDelegate"));
CarlaSettingsDelegate = CreateDefaultSubobject<UCarlaSettingsDelegate>(TEXT("CarlaSettingsDelegate"));
}
@ -82,6 +84,10 @@ void ATheNewCarlaGameModeBase::InitGame(
Episode->WorldObserver->SetStream(GameInstance->GetServer().OpenMultiStream());
SpawnActorFactories();
// make connection between Episode and Recorder
Recorder->SetEpisode(Episode);
Episode->SetRecorder(Recorder);
}
void ATheNewCarlaGameModeBase::RestartPlayer(AController *NewPlayer)
@ -113,6 +119,7 @@ void ATheNewCarlaGameModeBase::Tick(float DeltaSeconds)
Super::Tick(DeltaSeconds);
GameInstance->Tick(DeltaSeconds);
if (Recorder) Recorder->Tick(DeltaSeconds);
}
void ATheNewCarlaGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)

View File

@ -9,6 +9,7 @@
#include "Carla/Actor/CarlaActorFactory.h"
#include "Carla/Game/CarlaEpisode.h"
#include "Carla/Game/CarlaGameInstance.h"
#include "Carla/Game/CarlaRecorder.h"
#include "Carla/Game/TaggerDelegate.h"
#include "Carla/Settings/CarlaSettingsDelegate.h"
#include "Carla/Weather/Weather.h"
@ -62,6 +63,9 @@ private:
UPROPERTY()
UCarlaEpisode *Episode = nullptr;
UPROPERTY()
ACarlaRecorder *Recorder = nullptr;
/// The class of Weather to spawn.
UPROPERTY(Category = "CARLA Game Mode", EditAnywhere)
TSubclassOf<AWeather> WeatherClass;

View File

@ -14,9 +14,6 @@
#include <compiler/disable-ue4-macros.h>
#include <carla/sensor/SensorRegistry.h>
#include <carla/recorder/Recorder.h>
#include <carla/recorder/RecorderPosition.h>
#include <carla/recorder/RecorderState.h>
#include <carla/sensor/data/ActorDynamicState.h>
#include <compiler/enable-ue4-macros.h>
@ -153,51 +150,4 @@ void AWorldObserver::Tick(float DeltaSeconds)
);
AsyncStream.Send(*this, std::move(buffer));
// check if recording
if (Episode->GetRecorder().isEnabled()) {
const FActorRegistry &reg = Episode->GetActorRegistry();
// get positions
for (TActorIterator<ACarlaWheeledVehicle> It(GetWorld()); It; ++It)
{
ACarlaWheeledVehicle *Actor = *It;
check(Actor != nullptr);
carla::recorder::RecorderPosition recPos {
reg.Find(Actor).GetActorId(),
Actor->GetActorTransform()
};
Episode->GetRecorder().addPosition(std::move(recPos));
}
// get states
for (TActorIterator<ATrafficSignBase> It(GetWorld()); It; ++It)
{
ATrafficSignBase *Actor = *It;
check(Actor != nullptr);
auto TrafficLight = Cast<ATrafficLightBase>(Actor);
if (TrafficLight != nullptr)
{
carla::recorder::RecorderStateTrafficLight recTraffic {
reg.Find(Actor).GetActorId(),
TrafficLight->GetTimeIsFrozen(),
TrafficLight->GetElapsedTime(),
static_cast<char>(TrafficLight->GetTrafficLightState())
};
Episode->GetRecorder().addState(std::move(recTraffic));
}
// FActorDescription Description;
// Description.Id = UCarlaEpisode_GetTrafficSignId(Actor->GetTrafficSignState());
// Description.Class = Actor->GetClass();
// ActorDispatcher->RegisterActor(*Actor, Description);
}
// write
Episode->GetRecorder().write();
}
// replayer
if (Episode->GetReplayer().isEnabled())
Episode->GetReplayer().tick(DeltaSeconds);
}

View File

@ -556,24 +556,24 @@ void FTheNewCarlaServer::FPimpl::BindActions()
Server.BindSync("stop_recorder", [this]() -> R<void> {
REQUIRE_CARLA_EPISODE();
Episode->GetRecorder().stop();
Episode->GetRecorder()->Stop();
return R<void>::Success();
});
Server.BindSync("show_recorder_file_info", [this](std::string name) -> R<std::string> {
REQUIRE_CARLA_EPISODE();
return R<std::string>(Episode->GetRecorder().showFileInfo(
carla::rpc::FromFString(FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir())),
name));
return R<std::string>(Episode->GetRecorder()->ShowFileInfo(
carla::rpc::FromFString(FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir())),
name));
});
Server.BindSync("replay_file", [this](std::string name, double start, double duration) -> R<std::string> {
REQUIRE_CARLA_EPISODE();
return R<std::string>(Episode->GetRecorder().replayFile(
carla::rpc::FromFString(FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir())),
name,
start,
duration));
return R<std::string>(Episode->GetRecorder()->ReplayFile(
carla::rpc::FromFString(FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir())),
name,
start,
duration));
});
Server.BindSync("draw_debug_shape", [this](const cr::DebugShape &shape) -> R<void>
@ -654,4 +654,4 @@ FDataMultiStream FTheNewCarlaServer::OpenMultiStream() const
{
check(Pimpl != nullptr);
return Pimpl->StreamingServer.MakeMultiStream();
}
}