mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-22 11:18:22 -05:00
Merge branch 'master' into feature/jwst-update
This commit is contained in:
@@ -82,7 +82,6 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/network/parallelconnection.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/network/parallelpeer.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/network/parallelpeer_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/network/parallelserver.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/properties/optionproperty.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/properties/property.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/properties/propertyowner.cpp
|
||||
@@ -262,7 +261,6 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/navigation/waypoint.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelpeer.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelserver.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/messagestructures.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/messagestructureshelper.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/properties/listproperty.h
|
||||
|
||||
@@ -1659,8 +1659,14 @@ void OpenSpaceEngine::removeModeChangeCallback(CallbackHandle handle) {
|
||||
|
||||
void setCameraFromProfile(const Profile& p) {
|
||||
if (!p.camera.has_value()) {
|
||||
throw ghoul::RuntimeError("No 'camera' entry exists in the startup profile");
|
||||
// If the camera is not specified, we want to set it to a sensible default value
|
||||
interaction::NavigationState nav;
|
||||
nav.anchor = "Root";
|
||||
nav.referenceFrame = "Root";
|
||||
global::navigationHandler->setNavigationStateNextFrame(nav);
|
||||
return;
|
||||
}
|
||||
|
||||
std::visit(
|
||||
overloaded{
|
||||
[](const Profile::CameraNavState& navStateProfile) {
|
||||
|
||||
+106
-51
@@ -40,6 +40,7 @@
|
||||
#include <openspace/util/universalhelpers.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/interpolator.h>
|
||||
#include <glm/ext/quaternion_relational.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr const char _loggerCat[] = "Path";
|
||||
@@ -131,7 +132,6 @@ Path::Path(Waypoint start, Waypoint end, Type type,
|
||||
|
||||
// We now know how long it took to traverse the path. Use that
|
||||
_speedFactorFromDuration = _progressedTime / *duration;
|
||||
|
||||
resetPlaybackVariables();
|
||||
}
|
||||
}
|
||||
@@ -161,23 +161,7 @@ CameraPose Path::traversePath(double dt, float speedScale) {
|
||||
if (_type == Type::Linear) {
|
||||
// Special handling of linear paths, so that it can be used when we are
|
||||
// traversing very large distances without introducing precision problems
|
||||
const glm::dvec3 prevPosToEnd = _prevPose.position - _end.position();
|
||||
const double remainingDistance = glm::length(prevPosToEnd);
|
||||
|
||||
// Actual displacement may not be bigger than remaining distance
|
||||
if (displacement > remainingDistance) {
|
||||
displacement = remainingDistance;
|
||||
_traveledDistance = pathLength();
|
||||
_shouldQuit = true;
|
||||
return _end.pose();
|
||||
}
|
||||
|
||||
// Just move along the line from the current position to the target
|
||||
newPose.position = _prevPose.position -
|
||||
displacement * glm::normalize(prevPosToEnd);
|
||||
|
||||
const double relativeDistance = _traveledDistance / pathLength();
|
||||
newPose.rotation = interpolateRotation(relativeDistance);
|
||||
newPose = linearInterpolatedPose(_traveledDistance, displacement);
|
||||
}
|
||||
else {
|
||||
if (std::abs(prevDistance - _traveledDistance) < LengthEpsilon) {
|
||||
@@ -204,7 +188,14 @@ bool Path::hasReachedEnd() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (_traveledDistance / pathLength()) >= 1.0;
|
||||
bool isPositionFinished = (_traveledDistance / pathLength()) >= 1.0;
|
||||
bool isRotationFinished = glm::all(glm::equal(
|
||||
_prevPose.rotation,
|
||||
_end.rotation(),
|
||||
glm::epsilon<double>()
|
||||
));
|
||||
|
||||
return isPositionFinished && isRotationFinished;
|
||||
}
|
||||
|
||||
void Path::resetPlaybackVariables() {
|
||||
@@ -214,6 +205,28 @@ void Path::resetPlaybackVariables() {
|
||||
_shouldQuit = false;
|
||||
}
|
||||
|
||||
CameraPose Path::linearInterpolatedPose(double distance, double displacement) {
|
||||
ghoul_assert(_type == Type::Linear, "Path type must be linear");
|
||||
const double relativeDistance = distance / pathLength();
|
||||
const glm::dvec3 prevPosToEnd = _prevPose.position - _end.position();
|
||||
const double remainingDistance = glm::length(prevPosToEnd);
|
||||
CameraPose pose;
|
||||
|
||||
// Actual displacement may not be bigger than remaining distance
|
||||
if (displacement > remainingDistance) {
|
||||
_traveledDistance = pathLength();
|
||||
pose.position = _end.position();
|
||||
}
|
||||
else {
|
||||
// Just move along line from the current position to the target
|
||||
const glm::dvec3 lineDir = glm::normalize(prevPosToEnd);
|
||||
pose.position = _prevPose.position - displacement * lineDir;
|
||||
}
|
||||
|
||||
pose.rotation = linearPathRotation(relativeDistance);
|
||||
return pose;
|
||||
}
|
||||
|
||||
CameraPose Path::interpolatedPose(double distance) const {
|
||||
const double relativeDistance = distance / pathLength();
|
||||
CameraPose cs;
|
||||
@@ -227,6 +240,8 @@ glm::dquat Path::interpolateRotation(double t) const {
|
||||
case Type::AvoidCollision:
|
||||
return easedSlerpRotation(t);
|
||||
case Type::Linear:
|
||||
// @TODO (2022-03-29, emmbr) Fix so that rendering the rotation of linear
|
||||
// paths works again. I.e. openspace.debugging.renderCameraPath
|
||||
return linearPathRotation(t);
|
||||
case Type::ZoomOutOverview:
|
||||
case Type::AvoidCollisionWithLookAt:
|
||||
@@ -243,45 +258,59 @@ glm::dquat Path::easedSlerpRotation(double t) const {
|
||||
}
|
||||
|
||||
glm::dquat Path::linearPathRotation(double t) const {
|
||||
const double tHalf = 0.5;
|
||||
const glm::dvec3 a = ghoul::viewDirection(_start.rotation());
|
||||
const glm::dvec3 b = ghoul::viewDirection(_end.rotation());
|
||||
const double angle = std::acos(glm::dot(a, b)); // assumes length 1.0 for a & b
|
||||
|
||||
const glm::dvec3 endNodePos = _end.node()->worldPosition();
|
||||
const glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
|
||||
// Seconds per pi angles. Per default, it takes 5 seconds to turn 90 degrees
|
||||
double factor = 5.0 / glm::half_pi<double>();
|
||||
factor *= global::navigationHandler->pathNavigator().linearRotationSpeedFactor();
|
||||
|
||||
if (t < tHalf) {
|
||||
// Interpolate to look at target
|
||||
const glm::dvec3 halfWayPosition = _curve->positionAt(tHalf);
|
||||
const glm::dquat q = ghoul::lookAtQuaternion(halfWayPosition, endNodePos, endUp);
|
||||
double turnDuration = std::max(angle * factor, 1.0); // Always at least 1 second
|
||||
const double time = glm::clamp(_progressedTime / turnDuration, 0.0, 1.0);
|
||||
return easedSlerpRotation(time);
|
||||
|
||||
const double tScaled = ghoul::sineEaseInOut(t / tHalf);
|
||||
return glm::slerp(_start.rotation(), q, tScaled);
|
||||
}
|
||||
// @TODO (2022-03-18, emmbr) Leaving this for now, as something similar might have to
|
||||
// be implemented for navigation states. But should be removed/reimplemented
|
||||
|
||||
// This distance is guaranteed to be strictly decreasing for linear paths
|
||||
const double distanceToEnd = glm::distance(_prevPose.position, _end.position());
|
||||
//const glm::dvec3 endNodePos = _end.node()->worldPosition();
|
||||
//const glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
|
||||
|
||||
// Determine the distance at which to start interpolating to the target rotation.
|
||||
// The magic numbers here are just randomly picked constants, set to make the
|
||||
// resulting rotation look ok-ish
|
||||
double closingUpDistance = 10.0 * _end.validBoundingSphere();
|
||||
if (pathLength() < 2.0 * closingUpDistance) {
|
||||
closingUpDistance = 0.2 * pathLength();
|
||||
}
|
||||
//const double tHalf = 0.5;
|
||||
//if (t < tHalf) {
|
||||
// // Interpolate to look at target
|
||||
// const glm::dvec3 halfWayPosition = _curve->positionAt(tHalf);
|
||||
// const glm::dquat q = ghoul::lookAtQuaternion(halfWayPosition, endNodePos, endUp);
|
||||
|
||||
if (distanceToEnd < closingUpDistance) {
|
||||
// Interpolate to target rotation
|
||||
const double tScaled = ghoul::sineEaseInOut(1.0 - distanceToEnd / closingUpDistance);
|
||||
// const double tScaled = ghoul::sineEaseInOut(t / tHalf);
|
||||
// return glm::slerp(_start.rotation(), q, tScaled);
|
||||
//}
|
||||
|
||||
// Compute a position in front of the camera at the end orientation
|
||||
const double inFrontDistance = glm::distance(_end.position(), endNodePos);
|
||||
const glm::dvec3 viewDir = ghoul::viewDirection(_end.rotation());
|
||||
const glm::dvec3 inFrontOfEnd = _end.position() + inFrontDistance * viewDir;
|
||||
const glm::dvec3 lookAtPos = ghoul::interpolateLinear(tScaled, endNodePos, inFrontOfEnd);
|
||||
return ghoul::lookAtQuaternion(_prevPose.position, lookAtPos, endUp);
|
||||
}
|
||||
//// This distance is guaranteed to be strictly decreasing for linear paths
|
||||
//const double distanceToEnd = glm::distance(_prevPose.position, _end.position());
|
||||
|
||||
// Keep looking at the end node
|
||||
return ghoul::lookAtQuaternion(_prevPose.position, endNodePos, endUp);
|
||||
//// Determine the distance at which to start interpolating to the target rotation.
|
||||
//// The magic numbers here are just randomly picked constants, set to make the
|
||||
//// resulting rotation look ok-ish
|
||||
//double closingUpDistance = 10.0 * _end.validBoundingSphere();
|
||||
//if (pathLength() < 2.0 * closingUpDistance) {
|
||||
// closingUpDistance = 0.2 * pathLength();
|
||||
//}
|
||||
|
||||
//if (distanceToEnd < closingUpDistance) {
|
||||
// // Interpolate to target rotation
|
||||
// const double tScaled = ghoul::sineEaseInOut(1.0 - distanceToEnd / closingUpDistance);
|
||||
|
||||
// // Compute a position in front of the camera at the end orientation
|
||||
// const double inFrontDistance = glm::distance(_end.position(), endNodePos);
|
||||
// const glm::dvec3 viewDir = ghoul::viewDirection(_end.rotation());
|
||||
// const glm::dvec3 inFrontOfEnd = _end.position() + inFrontDistance * viewDir;
|
||||
// const glm::dvec3 lookAtPos = ghoul::interpolateLinear(tScaled, endNodePos, inFrontOfEnd);
|
||||
// return ghoul::lookAtQuaternion(_prevPose.position, lookAtPos, endUp);
|
||||
//}
|
||||
|
||||
//// Keep looking at the end node
|
||||
//return ghoul::lookAtQuaternion(_prevPose.position, endNodePos, endUp);
|
||||
}
|
||||
|
||||
glm::dquat Path::lookAtTargetsRotation(double t) const {
|
||||
@@ -350,8 +379,17 @@ double Path::speedAlongPath(double traveledDistance) const {
|
||||
double startUpDistance = DampenDistanceFactor * _start.validBoundingSphere();
|
||||
double closeUpDistance = DampenDistanceFactor * _end.validBoundingSphere();
|
||||
|
||||
// Kind of an ugly workaround to make damping behave over very long paths, and/or
|
||||
// where the target nodes might have large bounding spheres. The current max is set
|
||||
// based on the order of magnitude of the solar system, which ofc is very specific to
|
||||
// our space content...
|
||||
// @TODO (2022-03-22, emmbr) Come up with a better more general solution
|
||||
constexpr const double MaxDistance = 1E12;
|
||||
startUpDistance = glm::min(MaxDistance, startUpDistance);
|
||||
closeUpDistance = glm::min(MaxDistance, closeUpDistance);
|
||||
|
||||
if (pathLength() < startUpDistance + closeUpDistance) {
|
||||
startUpDistance = 0.49 * pathLength(); // a little less than half
|
||||
startUpDistance = 0.4 * pathLength(); // a little less than half
|
||||
closeUpDistance = startUpDistance;
|
||||
}
|
||||
|
||||
@@ -619,6 +657,23 @@ Path createPathFromDictionary(const ghoul::Dictionary& dictionary,
|
||||
p.useTargetUpDirection.value_or(false)
|
||||
};
|
||||
|
||||
double startToTargetCenterDistance = glm::distance(
|
||||
startPoint.position(),
|
||||
targetNode->worldPosition()
|
||||
);
|
||||
|
||||
// Use a linear path if camera start is within the bounding sphere
|
||||
const PathNavigator& navigator = global::navigationHandler->pathNavigator();
|
||||
const double bs = navigator.findValidBoundingSphere(targetNode);
|
||||
bool withinTargetBoundingSphere = startToTargetCenterDistance < bs;
|
||||
if (withinTargetBoundingSphere) {
|
||||
LINFO(
|
||||
"Camera is within the bounding sphere of the target node. "
|
||||
"Using linear path"
|
||||
);
|
||||
type = Path::Type::Linear;
|
||||
}
|
||||
|
||||
waypoints = { computeWaypointFromNodeInfo(info, startPoint, type) };
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace {
|
||||
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
|
||||
"SpeedScale",
|
||||
"Speed Scale",
|
||||
"Scale factor that the speed will be mulitplied with during path traversal. "
|
||||
"Scale factor that the speed will be multiplied with during path traversal. "
|
||||
"Can be used to speed up or slow down the camera motion, depending on if the "
|
||||
"value is larger than or smaller than one."
|
||||
};
|
||||
@@ -90,6 +90,14 @@ namespace {
|
||||
"object."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo RotationSpeedFactorInfo = {
|
||||
"RotationSpeedFactor",
|
||||
"Rotation Speed Factor (Linear Path)",
|
||||
"Affects how fast the camera rotates to the target rotation during a linear "
|
||||
"path. A value of 1 means that the camera will rotate 90 degrees in about 5 "
|
||||
"seconds. A value of 2 means twice that fast, and so on."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo =
|
||||
{
|
||||
"MinimalValidBoundingSphere",
|
||||
@@ -119,6 +127,7 @@ PathNavigator::PathNavigator()
|
||||
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
|
||||
, _applyIdleBehaviorOnFinish(IdleBehaviorOnFinishInfo, false)
|
||||
, _arrivalDistanceFactor(ArrivalDistanceFactorInfo, 2.0, 0.1, 20.0)
|
||||
, _linearRotationSpeedFactor(RotationSpeedFactorInfo, 1.f, 0.1f, 2.f)
|
||||
, _minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
|
||||
, _relevantNodeTags(RelevantNodeTagsInfo)
|
||||
{
|
||||
@@ -134,6 +143,7 @@ PathNavigator::PathNavigator()
|
||||
addProperty(_speedScale);
|
||||
addProperty(_applyIdleBehaviorOnFinish);
|
||||
addProperty(_arrivalDistanceFactor);
|
||||
addProperty(_linearRotationSpeedFactor);
|
||||
addProperty(_minValidBoundingSphere);
|
||||
|
||||
_relevantNodeTags = std::vector<std::string>{
|
||||
@@ -166,6 +176,10 @@ double PathNavigator::arrivalDistanceFactor() const {
|
||||
return _arrivalDistanceFactor;
|
||||
}
|
||||
|
||||
float PathNavigator::linearRotationSpeedFactor() const {
|
||||
return _linearRotationSpeedFactor;
|
||||
}
|
||||
|
||||
bool PathNavigator::hasCurrentPath() const {
|
||||
return _currentPath != nullptr;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace {
|
||||
|
||||
namespace openspace {
|
||||
|
||||
const unsigned int ParallelConnection::ProtocolVersion = 5;
|
||||
// Gonna do some UTF-like magic once we reach 255 to introduce a second byte or something
|
||||
const uint8_t ParallelConnection::ProtocolVersion = 6;
|
||||
|
||||
ParallelConnection::Message::Message(MessageType t, std::vector<char> c)
|
||||
: type(t)
|
||||
@@ -52,8 +53,9 @@ ParallelConnection::DataMessage::DataMessage(datamessagestructures::Type t,
|
||||
, content(std::move(c))
|
||||
{}
|
||||
|
||||
ParallelConnection::ConnectionLostError::ConnectionLostError()
|
||||
ParallelConnection::ConnectionLostError::ConnectionLostError(bool shouldLogError_)
|
||||
: ghoul::RuntimeError("Parallel connection lost", "ParallelConnection")
|
||||
, shouldLogError(shouldLogError_)
|
||||
{}
|
||||
|
||||
ParallelConnection::ParallelConnection(std::unique_ptr<ghoul::io::TcpSocket> socket)
|
||||
@@ -65,14 +67,14 @@ bool ParallelConnection::isConnectedOrConnecting() const {
|
||||
}
|
||||
|
||||
void ParallelConnection::sendDataMessage(const DataMessage& dataMessage) {
|
||||
const uint32_t dataMessageTypeOut = static_cast<uint32_t>(dataMessage.type);
|
||||
const uint8_t dataMessageTypeOut = static_cast<uint8_t>(dataMessage.type);
|
||||
const double dataMessageTimestamp = dataMessage.timestamp;
|
||||
|
||||
std::vector<char> messageContent;
|
||||
messageContent.insert(
|
||||
messageContent.end(),
|
||||
reinterpret_cast<const char*>(&dataMessageTypeOut),
|
||||
reinterpret_cast<const char*>(&dataMessageTypeOut) + sizeof(uint32_t)
|
||||
reinterpret_cast<const char*>(&dataMessageTypeOut) + sizeof(uint8_t)
|
||||
);
|
||||
|
||||
messageContent.insert(
|
||||
@@ -90,7 +92,7 @@ void ParallelConnection::sendDataMessage(const DataMessage& dataMessage) {
|
||||
}
|
||||
|
||||
bool ParallelConnection::sendMessage(const Message& message) {
|
||||
const uint32_t messageTypeOut = static_cast<uint32_t>(message.type);
|
||||
const uint8_t messageTypeOut = static_cast<uint8_t>(message.type);
|
||||
const uint32_t messageSizeOut = static_cast<uint32_t>(message.content.size());
|
||||
std::vector<char> header;
|
||||
|
||||
@@ -100,12 +102,12 @@ bool ParallelConnection::sendMessage(const Message& message) {
|
||||
|
||||
header.insert(header.end(),
|
||||
reinterpret_cast<const char*>(&ProtocolVersion),
|
||||
reinterpret_cast<const char*>(&ProtocolVersion) + sizeof(uint32_t)
|
||||
reinterpret_cast<const char*>(&ProtocolVersion) + sizeof(uint8_t)
|
||||
);
|
||||
|
||||
header.insert(header.end(),
|
||||
reinterpret_cast<const char*>(&messageTypeOut),
|
||||
reinterpret_cast<const char*>(&messageTypeOut) + sizeof(uint32_t)
|
||||
reinterpret_cast<const char*>(&messageTypeOut) + sizeof(uint8_t)
|
||||
);
|
||||
|
||||
header.insert(header.end(),
|
||||
@@ -123,6 +125,7 @@ bool ParallelConnection::sendMessage(const Message& message) {
|
||||
}
|
||||
|
||||
void ParallelConnection::disconnect() {
|
||||
_shouldDisconnect = true;
|
||||
if (_socket) {
|
||||
_socket->disconnect();
|
||||
}
|
||||
@@ -136,7 +139,9 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
|
||||
// Header consists of...
|
||||
constexpr size_t HeaderSize =
|
||||
2 * sizeof(char) + // OS
|
||||
3 * sizeof(uint32_t); // Protocol version, message type and message size
|
||||
sizeof(uint8_t) + // Protocol version
|
||||
sizeof(uint8_t) + // Message type
|
||||
sizeof(uint32_t); // message size
|
||||
|
||||
// Create basic buffer for receiving first part of messages
|
||||
std::vector<char> headerBuffer(HeaderSize);
|
||||
@@ -144,20 +149,27 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
|
||||
|
||||
// Receive the header data
|
||||
if (!_socket->get(headerBuffer.data(), HeaderSize)) {
|
||||
LERROR("Failed to read header from socket. Disconencting.");
|
||||
throw ConnectionLostError();
|
||||
// The `get` call is blocking until something happens, so we might end up here if
|
||||
// the socket properly closed or if the loading legitimately failed
|
||||
if (_shouldDisconnect) {
|
||||
throw ConnectionLostError(false);
|
||||
}
|
||||
else {
|
||||
LERROR("Failed to read header from socket. Disconnecting");
|
||||
throw ConnectionLostError();
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that header matches this version of OpenSpace
|
||||
if (!(headerBuffer[0] == 'O' && headerBuffer[1] == 'S')) {
|
||||
LERROR("Expected to read message header 'OS' from socket.");
|
||||
LERROR("Expected to read message header 'OS' from socket");
|
||||
throw ConnectionLostError();
|
||||
}
|
||||
|
||||
size_t offset = 2;
|
||||
const uint32_t protocolVersionIn =
|
||||
*reinterpret_cast<uint32_t*>(headerBuffer.data() + offset);
|
||||
offset += sizeof(uint32_t);
|
||||
const uint8_t protocolVersionIn =
|
||||
*reinterpret_cast<uint8_t*>(headerBuffer.data() + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
|
||||
if (protocolVersionIn != ProtocolVersion) {
|
||||
LERROR(fmt::format(
|
||||
@@ -168,9 +180,9 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
|
||||
throw ConnectionLostError();
|
||||
}
|
||||
|
||||
const uint32_t messageTypeIn =
|
||||
*reinterpret_cast<uint32_t*>(headerBuffer.data() + offset);
|
||||
offset += sizeof(uint32_t);
|
||||
const uint8_t messageTypeIn =
|
||||
*reinterpret_cast<uint8_t*>(headerBuffer.data() + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
|
||||
const uint32_t messageSizeIn =
|
||||
*reinterpret_cast<uint32_t*>(headerBuffer.data() + offset);
|
||||
@@ -181,7 +193,7 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
|
||||
// Receive the payload
|
||||
messageBuffer.resize(messageSize);
|
||||
if (!_socket->get(messageBuffer.data(), messageSize)) {
|
||||
LERROR("Failed to read message from socket. Disconencting.");
|
||||
LERROR("Failed to read message from socket. Disconnecting");
|
||||
throw ConnectionLostError();
|
||||
}
|
||||
|
||||
|
||||
@@ -163,31 +163,59 @@ void ParallelPeer::disconnect() {
|
||||
}
|
||||
|
||||
void ParallelPeer::sendAuthentication() {
|
||||
std::string name = _name;
|
||||
// Length of this nodes name
|
||||
const uint32_t nameLength = static_cast<uint32_t>(name.length());
|
||||
std::string password = _password;
|
||||
if (password.size() > std::numeric_limits<uint16_t>::max()) {
|
||||
password.resize(std::numeric_limits<uint16_t>::max());
|
||||
}
|
||||
const uint16_t passwordSize = static_cast<uint16_t>(password.size());
|
||||
|
||||
// Total size of the buffer: (passcode + namelength + name)
|
||||
const size_t size = sizeof(uint64_t) + sizeof(uint32_t) + nameLength;
|
||||
std::string hostPassword = _hostPassword;
|
||||
if (hostPassword.size() > std::numeric_limits<uint16_t>::max()) {
|
||||
hostPassword.resize(std::numeric_limits<uint16_t>::max());
|
||||
}
|
||||
const uint16_t hostPasswordSize = static_cast<uint16_t>(hostPassword.size());
|
||||
|
||||
std::string name = _name;
|
||||
if (name.size() > std::numeric_limits<uint8_t>::max()) {
|
||||
name.resize(std::numeric_limits<uint8_t>::max());
|
||||
}
|
||||
const uint8_t nameLength = static_cast<uint8_t>(name.length());
|
||||
|
||||
|
||||
// Total size of the buffer
|
||||
const size_t size =
|
||||
sizeof(uint16_t) + // password length
|
||||
passwordSize + // password
|
||||
sizeof(uint16_t) + // host password length
|
||||
hostPasswordSize + // host password
|
||||
sizeof(uint8_t) + // name length
|
||||
nameLength; // name
|
||||
|
||||
// Create and reserve buffer
|
||||
std::vector<char> buffer;
|
||||
buffer.reserve(size);
|
||||
|
||||
const uint64_t passCode = std::hash<std::string>{}(_password.value());
|
||||
|
||||
// Write the hashed password to buffer
|
||||
// Write the password to buffer
|
||||
buffer.insert(
|
||||
buffer.end(),
|
||||
reinterpret_cast<const char*>(&passCode),
|
||||
reinterpret_cast<const char*>(&passCode) + sizeof(uint64_t)
|
||||
reinterpret_cast<const char*>(&passwordSize),
|
||||
reinterpret_cast<const char*>(&passwordSize) + sizeof(uint16_t)
|
||||
);
|
||||
buffer.insert(buffer.end(), password.begin(), password.end());
|
||||
|
||||
// Write the host password to buffer
|
||||
buffer.insert(
|
||||
buffer.end(),
|
||||
reinterpret_cast<const char*>(&hostPasswordSize),
|
||||
reinterpret_cast<const char*>(&hostPasswordSize) + sizeof(uint16_t)
|
||||
);
|
||||
buffer.insert(buffer.end(), hostPassword.begin(), hostPassword.end());
|
||||
|
||||
// Write the length of the nodes name to buffer
|
||||
buffer.insert(
|
||||
buffer.end(),
|
||||
reinterpret_cast<const char*>(&nameLength),
|
||||
reinterpret_cast<const char*>(&nameLength) + sizeof(uint32_t)
|
||||
reinterpret_cast<const char*>(&nameLength) + sizeof(uint8_t)
|
||||
);
|
||||
|
||||
// Write this node's name to buffer
|
||||
@@ -265,8 +293,8 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message) {
|
||||
size_t offset = 0;
|
||||
|
||||
// The type of data message received
|
||||
const uint32_t type = *(reinterpret_cast<const uint32_t*>(message.data() + offset));
|
||||
offset += sizeof(uint32_t);
|
||||
const uint8_t type = *(reinterpret_cast<const uint8_t*>(message.data() + offset));
|
||||
offset += sizeof(uint8_t);
|
||||
|
||||
const double timestamp = *(reinterpret_cast<const double*>(message.data() + offset));
|
||||
offset += sizeof(double);
|
||||
@@ -363,19 +391,19 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message) {
|
||||
}
|
||||
|
||||
void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& message) {
|
||||
if (message.size() < 2 * sizeof(uint32_t)) {
|
||||
if (message.size() < 2 * sizeof(uint8_t)) {
|
||||
LERROR("Malformed connection status message");
|
||||
return;
|
||||
}
|
||||
size_t pointer = 0;
|
||||
uint32_t statusIn = *(reinterpret_cast<const uint32_t*>(&message[pointer]));
|
||||
const uint8_t statusIn = *(reinterpret_cast<const uint8_t*>(&message[pointer]));
|
||||
const ParallelConnection::Status status = static_cast<ParallelConnection::Status>(
|
||||
statusIn
|
||||
);
|
||||
pointer += sizeof(uint32_t);
|
||||
pointer += sizeof(uint8_t);
|
||||
|
||||
const size_t hostNameSize = *(reinterpret_cast<const uint32_t*>(&message[pointer]));
|
||||
pointer += sizeof(uint32_t);
|
||||
const uint8_t hostNameSize = *(reinterpret_cast<const uint8_t*>(&message[pointer]));
|
||||
pointer += sizeof(uint8_t);
|
||||
|
||||
if (hostNameSize > message.size() - pointer) {
|
||||
LERROR("Malformed connection status message");
|
||||
@@ -409,8 +437,7 @@ void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& mess
|
||||
global::timeManager->clearKeyframes();
|
||||
}
|
||||
|
||||
void ParallelPeer::nConnectionsMessageReceived(const std::vector<char>& message)
|
||||
{
|
||||
void ParallelPeer::nConnectionsMessageReceived(const std::vector<char>& message) {
|
||||
if (message.size() < sizeof(uint32_t)) {
|
||||
LERROR("Malformed host info message");
|
||||
return;
|
||||
@@ -424,8 +451,10 @@ void ParallelPeer::handleCommunication() {
|
||||
try {
|
||||
ParallelConnection::Message m = _connection.receiveMessage();
|
||||
queueInMessage(m);
|
||||
} catch (const ParallelConnection::ConnectionLostError&) {
|
||||
LERROR("Parallel connection lost");
|
||||
} catch (const ParallelConnection::ConnectionLostError& e) {
|
||||
if (e.shouldLogError) {
|
||||
LERROR("Parallel connection lost");
|
||||
}
|
||||
}
|
||||
}
|
||||
setStatus(ParallelConnection::Status::Disconnected);
|
||||
@@ -445,12 +474,14 @@ void ParallelPeer::setName(std::string name) {
|
||||
|
||||
void ParallelPeer::requestHostship() {
|
||||
std::vector<char> buffer;
|
||||
uint64_t passwordHash = std::hash<std::string>{}(_hostPassword);
|
||||
std::string hostPw = _hostPassword;
|
||||
uint16_t hostPwSize = static_cast<uint16_t>(hostPw.size());
|
||||
buffer.insert(
|
||||
buffer.end(),
|
||||
reinterpret_cast<char*>(&passwordHash),
|
||||
reinterpret_cast<char*>(&passwordHash) + sizeof(uint64_t)
|
||||
reinterpret_cast<const char*>(&hostPwSize),
|
||||
reinterpret_cast<const char*>(&hostPwSize) + sizeof(uint16_t)
|
||||
);
|
||||
buffer.insert(buffer.end(), hostPw.begin(), hostPw.end());
|
||||
|
||||
_connection.sendMessage(ParallelConnection::Message(
|
||||
ParallelConnection::MessageType::HostshipRequest,
|
||||
@@ -504,7 +535,7 @@ void ParallelPeer::resetTimeOffset() {
|
||||
void ParallelPeer::preSynchronization() {
|
||||
ZoneScoped
|
||||
|
||||
std::unique_lock<std::mutex> unqlock(_receiveBufferMutex);
|
||||
std::unique_lock<std::mutex> unlock(_receiveBufferMutex);
|
||||
while (!_receiveBuffer.empty()) {
|
||||
ParallelConnection::Message& message = _receiveBuffer.front();
|
||||
handleMessage(message);
|
||||
|
||||
@@ -1,426 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/network/parallelserver.h>
|
||||
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/io/socket/tcpsocket.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <functional>
|
||||
|
||||
// @TODO(abock): In the entire class remove std::shared_ptr<Peer> by const Peer& where
|
||||
// possible to simplify the interface
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "ParallelServer";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
void ParallelServer::start(int port, const std::string& password,
|
||||
const std::string& changeHostPassword)
|
||||
{
|
||||
_socketServer.listen(port);
|
||||
_passwordHash = std::hash<std::string>{}(password);
|
||||
_changeHostPasswordHash = std::hash<std::string>{}(changeHostPassword);
|
||||
|
||||
_serverThread = std::thread([this](){ handleNewPeers(); });
|
||||
_eventLoopThread = std::thread([this]() { eventLoop(); });
|
||||
}
|
||||
|
||||
void ParallelServer::setDefaultHostAddress(std::string defaultHostAddress) {
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
_defaultHostAddress = std::move(defaultHostAddress);
|
||||
}
|
||||
|
||||
std::string ParallelServer::defaultHostAddress() const {
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
return _defaultHostAddress;
|
||||
}
|
||||
|
||||
void ParallelServer::stop() {
|
||||
_shouldStop = true;
|
||||
_socketServer.close();
|
||||
}
|
||||
|
||||
void ParallelServer::handleNewPeers() {
|
||||
while (!_shouldStop) {
|
||||
std::unique_ptr<ghoul::io::TcpSocket> s = _socketServer.awaitPendingTcpSocket();
|
||||
|
||||
s->startStreams();
|
||||
|
||||
const size_t id = _nextConnectionId++;
|
||||
auto p = std::make_shared<Peer>(Peer{
|
||||
id,
|
||||
"",
|
||||
ParallelConnection(std::move(s)),
|
||||
ParallelConnection::Status::Connecting,
|
||||
std::thread()
|
||||
});
|
||||
auto it = _peers.emplace(p->id, p);
|
||||
it.first->second->thread = std::thread([this, id]() { handlePeer(id); });
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ParallelServer::Peer> ParallelServer::peer(size_t id) {
|
||||
std::lock_guard lock(_peerListMutex);
|
||||
const auto it = _peers.find(id);
|
||||
if (it == _peers.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void ParallelServer::handlePeer(size_t id) {
|
||||
while (!_shouldStop) {
|
||||
std::shared_ptr<Peer> p = peer(id);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p->parallelConnection.isConnectedOrConnecting()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ParallelConnection::Message m = p->parallelConnection.receiveMessage();
|
||||
PeerMessage msg;
|
||||
msg.peerId = id;
|
||||
msg.message = m;
|
||||
_incomingMessages.push(msg);
|
||||
}
|
||||
catch (const ParallelConnection::ConnectionLostError&) {
|
||||
LERROR(fmt::format("Connection lost to {}", p->id));
|
||||
PeerMessage msg;
|
||||
msg.peerId = id;
|
||||
msg.message = ParallelConnection::Message(
|
||||
ParallelConnection::MessageType::Disconnection, std::vector<char>()
|
||||
);
|
||||
_incomingMessages.push(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::eventLoop() {
|
||||
while (!_shouldStop) {
|
||||
PeerMessage pm = _incomingMessages.pop();
|
||||
handlePeerMessage(std::move(pm));
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::handlePeerMessage(PeerMessage peerMessage) {
|
||||
const size_t peerId = peerMessage.peerId;
|
||||
auto it = _peers.find(peerId);
|
||||
if (it == _peers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<Peer>& peer = it->second;
|
||||
|
||||
const ParallelConnection::MessageType type = peerMessage.message.type;
|
||||
std::vector<char>& data = peerMessage.message.content;
|
||||
switch (type) {
|
||||
case ParallelConnection::MessageType::Authentication:
|
||||
handleAuthentication(peer, std::move(data));
|
||||
break;
|
||||
case ParallelConnection::MessageType::Data:
|
||||
handleData(*peer, std::move(data));
|
||||
break;
|
||||
case ParallelConnection::MessageType::HostshipRequest:
|
||||
handleHostshipRequest(peer, std::move(data));
|
||||
break;
|
||||
case ParallelConnection::MessageType::HostshipResignation:
|
||||
handleHostshipResignation(*peer);
|
||||
break;
|
||||
case ParallelConnection::MessageType::Disconnection:
|
||||
disconnect(*peer);
|
||||
break;
|
||||
default:
|
||||
LERROR(fmt::format("Unsupported message type: {}", static_cast<int>(type)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::handleAuthentication(std::shared_ptr<Peer> peer,
|
||||
std::vector<char> message)
|
||||
{
|
||||
std::stringstream input(std::string(message.begin(), message.end()));
|
||||
|
||||
// 8 bytes passcode
|
||||
uint64_t passwordHash = 0;
|
||||
input.read(reinterpret_cast<char*>(&passwordHash), sizeof(uint64_t));
|
||||
|
||||
if (passwordHash != _passwordHash) {
|
||||
LERROR(fmt::format("Connection {} provided incorrect passcode.", peer->id));
|
||||
disconnect(*peer);
|
||||
return;
|
||||
}
|
||||
|
||||
// 4 bytes name size
|
||||
uint32_t nameSize = 0;
|
||||
input.read(reinterpret_cast<char*>(&nameSize), sizeof(uint32_t));
|
||||
|
||||
// <nameSize> bytes name
|
||||
std::string name(nameSize, static_cast<char>(0));
|
||||
input.read(&name[0], nameSize);
|
||||
|
||||
if (nameSize == 0) {
|
||||
name = "Anonymous";
|
||||
}
|
||||
|
||||
setName(*peer, name);
|
||||
|
||||
LINFO(fmt::format("Connection established with {} ('{}')", peer->id, name));
|
||||
|
||||
std::string defaultHostAddress;
|
||||
{
|
||||
std::lock_guard _hostMutex(_hostInfoMutex);
|
||||
defaultHostAddress = _defaultHostAddress;
|
||||
}
|
||||
if (_hostPeerId == 0 &&
|
||||
peer->parallelConnection.socket()->address() == defaultHostAddress)
|
||||
{
|
||||
// Directly promote the conenction to host (initialize) if there is no host, and
|
||||
// ip matches default host ip.
|
||||
LINFO(fmt::format("Connection {} directly promoted to host", peer->id));
|
||||
assignHost(peer);
|
||||
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
|
||||
// sendConnectionStatus(it->second) ?
|
||||
sendConnectionStatus(*peer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setToClient(*peer);
|
||||
}
|
||||
|
||||
setNConnections(nConnections() + 1);
|
||||
}
|
||||
|
||||
void ParallelServer::handleData(const Peer& peer, std::vector<char> data) {
|
||||
if (peer.id != _hostPeerId) {
|
||||
LINFO(fmt::format(
|
||||
"Ignoring connection {} trying to send data without being host", peer.id
|
||||
));
|
||||
}
|
||||
sendMessageToClients(ParallelConnection::MessageType::Data, data);
|
||||
}
|
||||
|
||||
void ParallelServer::handleHostshipRequest(std::shared_ptr<Peer> peer,
|
||||
std::vector<char> message)
|
||||
{
|
||||
std::stringstream input(std::string(message.begin(), message.end()));
|
||||
|
||||
LINFO(fmt::format("Connection {} requested hostship", peer->id));
|
||||
|
||||
uint64_t passwordHash = 0;
|
||||
input.read(reinterpret_cast<char*>(&passwordHash), sizeof(uint64_t));
|
||||
|
||||
if (passwordHash != _changeHostPasswordHash) {
|
||||
LERROR(fmt::format("Connection {} provided incorrect host password", peer->id));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t oldHostPeerId = 0;
|
||||
{
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
oldHostPeerId = _hostPeerId;
|
||||
}
|
||||
|
||||
if (oldHostPeerId == peer->id) {
|
||||
LINFO(fmt::format("Connection {} is already the host", peer->id));
|
||||
return;
|
||||
}
|
||||
|
||||
assignHost(peer);
|
||||
LINFO(fmt::format("Switched host from {} to {}", oldHostPeerId, peer->id));
|
||||
}
|
||||
|
||||
void ParallelServer::handleHostshipResignation(Peer& peer) {
|
||||
LINFO(fmt::format("Connection {} wants to resign its hostship", peer.id));
|
||||
|
||||
setToClient(peer);
|
||||
|
||||
LINFO(fmt::format("Connection {} resigned as host", peer.id));
|
||||
}
|
||||
|
||||
bool ParallelServer::isConnected(const Peer& peer) const {
|
||||
return peer.status != ParallelConnection::Status::Connecting &&
|
||||
peer.status != ParallelConnection::Status::Disconnected;
|
||||
}
|
||||
|
||||
void ParallelServer::sendMessage(Peer& peer, ParallelConnection::MessageType messageType,
|
||||
const std::vector<char>& message)
|
||||
{
|
||||
peer.parallelConnection.sendMessage({ messageType, message });
|
||||
}
|
||||
|
||||
void ParallelServer::sendMessageToAll(ParallelConnection::MessageType messageType,
|
||||
const std::vector<char>& message)
|
||||
{
|
||||
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
|
||||
if (isConnected(*it.second)) {
|
||||
it.second->parallelConnection.sendMessage({ messageType, message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::sendMessageToClients(ParallelConnection::MessageType messageType,
|
||||
const std::vector<char>& message)
|
||||
{
|
||||
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
|
||||
if (it.second->status == ParallelConnection::Status::ClientWithHost) {
|
||||
it.second->parallelConnection.sendMessage({ messageType, message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::disconnect(Peer& peer) {
|
||||
if (isConnected(peer)) {
|
||||
setNConnections(nConnections() - 1);
|
||||
}
|
||||
|
||||
size_t hostPeerId = 0;
|
||||
{
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
hostPeerId = _hostPeerId;
|
||||
}
|
||||
|
||||
// Make sure any disconnecting host is first degraded to client, in order to notify
|
||||
// other clients about host disconnection.
|
||||
if (peer.id == hostPeerId) {
|
||||
setToClient(peer);
|
||||
}
|
||||
|
||||
peer.parallelConnection.disconnect();
|
||||
peer.thread.join();
|
||||
_peers.erase(peer.id);
|
||||
}
|
||||
|
||||
void ParallelServer::setName(Peer& peer, std::string name) {
|
||||
peer.name = std::move(name);
|
||||
size_t hostPeerId = 0;
|
||||
{
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
hostPeerId = _hostPeerId;
|
||||
}
|
||||
|
||||
// Make sure everyone gets the new host name.
|
||||
if (peer.id == hostPeerId) {
|
||||
{
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
_hostName = peer.name;
|
||||
}
|
||||
|
||||
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
|
||||
// sendConnectionStatus(it->second) ?
|
||||
sendConnectionStatus(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::assignHost(std::shared_ptr<Peer> newHost) {
|
||||
{
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
std::shared_ptr<ParallelServer::Peer> oldHost = peer(_hostPeerId);
|
||||
|
||||
if (oldHost) {
|
||||
oldHost->status = ParallelConnection::Status::ClientWithHost;
|
||||
}
|
||||
_hostPeerId = newHost->id;
|
||||
_hostName = newHost->name;
|
||||
}
|
||||
newHost->status = ParallelConnection::Status::Host;
|
||||
|
||||
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
|
||||
if (it.second != newHost) {
|
||||
it.second->status = ParallelConnection::Status::ClientWithHost;
|
||||
}
|
||||
sendConnectionStatus(*it.second);
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::setToClient(Peer& peer) {
|
||||
if (peer.status == ParallelConnection::Status::Host) {
|
||||
{
|
||||
std::lock_guard lock(_hostInfoMutex);
|
||||
_hostPeerId = 0;
|
||||
_hostName.clear();
|
||||
}
|
||||
|
||||
// If host becomes client, make all clients hostless.
|
||||
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
|
||||
it.second->status = ParallelConnection::Status::ClientWithoutHost;
|
||||
sendConnectionStatus(*it.second);
|
||||
}
|
||||
}
|
||||
else {
|
||||
peer.status = (_hostPeerId > 0) ?
|
||||
ParallelConnection::Status::ClientWithHost :
|
||||
ParallelConnection::Status::ClientWithoutHost;
|
||||
sendConnectionStatus(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelServer::setNConnections(size_t nConnections) {
|
||||
_nConnections = nConnections;
|
||||
std::vector<char> data;
|
||||
const uint32_t n = static_cast<uint32_t>(_nConnections);
|
||||
data.insert(
|
||||
data.end(),
|
||||
reinterpret_cast<const char*>(&n),
|
||||
reinterpret_cast<const char*>(&n) + sizeof(uint32_t)
|
||||
);
|
||||
sendMessageToAll(ParallelConnection::MessageType::NConnections, data);
|
||||
}
|
||||
|
||||
void ParallelServer::sendConnectionStatus(Peer& peer) {
|
||||
std::vector<char> data;
|
||||
const uint32_t outStatus = static_cast<uint32_t>(peer.status);
|
||||
data.insert(
|
||||
data.end(),
|
||||
reinterpret_cast<const char*>(&outStatus),
|
||||
reinterpret_cast<const char*>(&outStatus) + sizeof(uint32_t)
|
||||
);
|
||||
|
||||
const uint32_t outHostNameSize = static_cast<uint32_t>(_hostName.size());
|
||||
data.insert(
|
||||
data.end(),
|
||||
reinterpret_cast<const char*>(&outHostNameSize),
|
||||
reinterpret_cast<const char*>(&outHostNameSize) + sizeof(uint32_t)
|
||||
);
|
||||
|
||||
data.insert(
|
||||
data.end(),
|
||||
_hostName.data(),
|
||||
_hostName.data() + outHostNameSize
|
||||
);
|
||||
|
||||
sendMessage(peer, ParallelConnection::MessageType::ConnectionStatus, data);
|
||||
}
|
||||
|
||||
size_t ParallelServer::nConnections() const {
|
||||
return _nConnections;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -1072,7 +1072,8 @@ scripting::LuaLibrary RenderEngine::luaLibrary() {
|
||||
{
|
||||
codegen::lua::AddScreenSpaceRenderable,
|
||||
codegen::lua::RemoveScreenSpaceRenderable,
|
||||
codegen::lua::TakeScreenshot
|
||||
codegen::lua::TakeScreenshot,
|
||||
codegen::lua::DpiScaling
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ namespace {
|
||||
return static_cast<int>(screenshotNumber);
|
||||
}
|
||||
|
||||
// Extracts the DPI scaling for either the GUI window or if there is no dedicated GUI
|
||||
// window, the first window.
|
||||
[[codegen::luawrap]] float dpiScaling() {
|
||||
return openspace::global::windowDelegate->osDpiScaling();
|
||||
}
|
||||
|
||||
#include "renderengine_lua_codegen.cpp"
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -343,6 +343,10 @@ bool AssetManager::loadAsset(Asset* asset, Asset* parent) {
|
||||
LERROR(fmt::format("Could not load asset {}: {}", asset->path(), e.message));
|
||||
return false;
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract meta information from the asset file if it was provided
|
||||
lua_getglobal(*_luaState, AssetGlobalVariableName);
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace {
|
||||
* Returns the paths to all loaded assets, loaded directly or indirectly, as a table
|
||||
* containing the paths to all loaded assets.
|
||||
*/
|
||||
[[codegen::luawrap]] std::vector<std::string> allAssets(std::string assetName) {
|
||||
[[codegen::luawrap]] std::vector<std::string> allAssets() {
|
||||
using namespace openspace;
|
||||
std::vector<const Asset*> as = global::openSpaceEngine->assetManager().allAssets();
|
||||
std::vector<std::string> res;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace {
|
||||
OS os = CpuCap.operatingSystem();
|
||||
|
||||
switch (os) {
|
||||
case OS::Windows10:
|
||||
case OS::Windows10or11:
|
||||
case OS::WindowsServer2016:
|
||||
case OS::WindowsVista:
|
||||
case OS::WindowsServer2008:
|
||||
|
||||
+11
-11
@@ -896,24 +896,24 @@ bool TimeManager::isPlayingBackSessionRecording() const {
|
||||
}
|
||||
|
||||
void TimeManager::setTimeFromProfile(const Profile& p) {
|
||||
Time t;
|
||||
|
||||
if (p.time.has_value()) {
|
||||
switch (p.time.value().type) {
|
||||
case Profile::Time::Type::Relative:
|
||||
t.setTimeRelativeFromProfile(p.time.value().value);
|
||||
break;
|
||||
case Profile::Time::Type::Relative:
|
||||
Time::setTimeRelativeFromProfile(p.time.value().value);
|
||||
break;
|
||||
|
||||
case Profile::Time::Type::Absolute:
|
||||
t.setTimeAbsoluteFromProfile(p.time.value().value);
|
||||
break;
|
||||
case Profile::Time::Type::Absolute:
|
||||
Time::setTimeAbsoluteFromProfile(p.time.value().value);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw ghoul::RuntimeError("No 'time' entry exists in the startup profile");
|
||||
// No value was specified so we are using 'now' instead
|
||||
std::string now = std::string(Time::now().UTC());
|
||||
Time::setTimeAbsoluteFromProfile(now);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user