diff --git a/include/openspace/network/parallelconnection.h b/include/openspace/network/parallelconnection.h index bb8de83310..e20ba4d9c4 100644 --- a/include/openspace/network/parallelconnection.h +++ b/include/openspace/network/parallelconnection.h @@ -88,7 +88,7 @@ namespace openspace{ void signalDisconnect(); - void update(double dt); + void preSynchronization(); enum MessageTypes{ Authentication=0, @@ -188,6 +188,10 @@ namespace openspace{ std::atomic _tryConnect; std::vector> _sendBuffer; std::mutex _sendBufferMutex; + + network::datamessagestructures::TimeKeyframe _latestTimeKeyframe; + std::mutex _timeKeyframeMutex; + std::atomic _latestTimeKeyframeValid; }; } // namespace network diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index cba2eced3f..16906e4494 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -86,18 +86,18 @@ public: * Sets the current time to the specified value in seconds past the J2000 epoch. This * value can be negative to represent dates before the epoch. * \param value The number of seconds after the J2000 epoch - * \param requireJump Wether or not the time change is big enough to require a time-jump, defaults to false + * \param requireJump Wether or not the time change is big enough to require a time-jump, defaults to true as most calls to set time will require recomputation of planetary paths etc. */ - void setTime(double value, bool requireJump = false); + void setTime(double value, bool requireJump = true); /** * Sets the current time to the specified value given as a Spice compliant string as * described in the Spice documentation * (http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/str2et_c.html) * \param time The time to be set as a date string - * \param requireJump Wether or not the time change is big enough to require a time-jump, defaults to false + * \param requireJump Wether or not the time change is big enough to require a time-jump, defaults to true as most calls to set time will require recomputation of planetary paths etc. */ - void setTime(std::string time, bool requireJump = false); + void setTime(std::string time, bool requireJump = true); /** * Returns the current time as the number of seconds past the J2000 epoch. If the diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 0e1bd1e13c..96d361787e 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -643,7 +643,7 @@ void OpenSpaceEngine::preSynchronization() { _renderEngine->preSynchronization(); - _parallelConnection->update(dt); + _parallelConnection->preSynchronization(); } } diff --git a/src/network/parallelconnection.cpp b/src/network/parallelconnection.cpp index af92a9f240..78edcd7062 100644 --- a/src/network/parallelconnection.cpp +++ b/src/network/parallelconnection.cpp @@ -87,7 +87,9 @@ namespace openspace { _isHost(false), _isConnected(false), _tryConnect(false), - _performDisconnect(false) + _performDisconnect(false), + _latestTimeKeyframeValid(false) + { //create handler thread _handlerThread = new (std::nothrow) std::thread(&ParallelConnection::threadManagement, this); @@ -541,10 +543,29 @@ namespace openspace { network::datamessagestructures::TimeKeyframe tf; tf.deserialize(buffer); - //set the time parameters based on recevied keyframe - Time::ref().setDeltaTime(tf._dt); - Time::ref().setPause(tf._paused); - Time::ref().setTime(tf._time, tf._requiresTimeJump); + //lock mutex and assign latest time keyframe parameters + _timeKeyframeMutex.lock(); + + _latestTimeKeyframe._dt = tf._dt; + _latestTimeKeyframe._time = tf._time; + _latestTimeKeyframe._paused = tf._paused; + + //ensure that we never miss a timejump + //if last keyframe required a jump and that keyframe has not been used yet + if(_latestTimeKeyframe._requiresTimeJump && _latestTimeKeyframeValid){ + //do nothing to the boolean. Old value must be executed + }else{ + //either the latest keyframe didnt require a jump, or we have already spent that keyframe. + //in either case we can go ahead and write the bool value of newest frame + _latestTimeKeyframe._requiresTimeJump = tf._requiresTimeJump; + } + + //unlock mutex + _timeKeyframeMutex.unlock(); + + //the keyframe is now valid for use + _latestTimeKeyframeValid.store(true); + break; } case network::datamessagestructures::ScriptData:{ @@ -917,42 +938,70 @@ namespace openspace { return true; } - void ParallelConnection::update(double dt){ + void ParallelConnection::preSynchronization(){ - //get current time parameters and create a keyframe - network::datamessagestructures::TimeKeyframe tf; - tf._dt = Time::ref().deltaTime(); - tf._paused = Time::ref().paused(); - tf._requiresTimeJump = Time::ref().timeJumped(); - tf._time = Time::ref().currentTime(); - - //create a buffer and serialize message - std::vector tbuffer; - tf.serialize(tbuffer); - - //get the size of the keyframebuffer - uint16_t msglen = static_cast(tbuffer.size()); - - uint16_t type = static_cast(network::datamessagestructures::PositionData); - - //create the full buffer - std::vector buffer; - buffer.reserve(headerSize() + sizeof(type) + sizeof(msglen) + msglen); - - //write header - writeHeader(buffer, MessageTypes::Data); - - //type of message - buffer.insert(buffer.end(), reinterpret_cast(&type), reinterpret_cast(&type) + sizeof(type)); - - //size of message - buffer.insert(buffer.end(), reinterpret_cast(&msglen), reinterpret_cast(&msglen) + sizeof(msglen)); - - //actual message - buffer.insert(buffer.end(), tbuffer.begin(), tbuffer.end()); - - //send message - queMessage(buffer); + //if we're the host + if(_isHost){ + //get current time parameters and create a keyframe + network::datamessagestructures::TimeKeyframe tf; + tf._dt = Time::ref().deltaTime(); + tf._paused = Time::ref().paused(); + tf._requiresTimeJump = Time::ref().timeJumped(); + tf._time = Time::ref().currentTime(); + + //create a buffer and serialize message + std::vector tbuffer; + tf.serialize(tbuffer); + + //get the size of the keyframebuffer + uint16_t msglen = static_cast(tbuffer.size()); + + //the type of data message + uint16_t type = static_cast(network::datamessagestructures::TimeData); + + //create the full buffer + std::vector buffer; + buffer.reserve(headerSize() + sizeof(type) + sizeof(msglen) + msglen); + + //write header + writeHeader(buffer, MessageTypes::Data); + + //type of message + buffer.insert(buffer.end(), reinterpret_cast(&type), reinterpret_cast(&type) + sizeof(type)); + + //size of message + buffer.insert(buffer.end(), reinterpret_cast(&msglen), reinterpret_cast(&msglen) + sizeof(msglen)); + + //actual message + buffer.insert(buffer.end(), tbuffer.begin(), tbuffer.end()); + + //send message + queMessage(buffer); + } + else{ + //if we're not the host and we have a valid keyframe (one that hasnt been used before) + if(_latestTimeKeyframeValid.load()){ + + //lock mutex and retrieve parameters from latest keyframe + _timeKeyframeMutex.lock(); + + double dt = _latestTimeKeyframe._dt; + double time = _latestTimeKeyframe._time; + bool jump = _latestTimeKeyframe._requiresTimeJump; + bool paused = _latestTimeKeyframe._paused; + + _timeKeyframeMutex.unlock(); + + //this keyframe is now spent + _latestTimeKeyframeValid.store(false); + + //assign latest params + Time::ref().setDeltaTime(dt); + Time::ref().setTime(time, jump); + Time::ref().setPause(paused); + + } + } } void ParallelConnection::broadcast(){ @@ -977,6 +1026,7 @@ namespace openspace { //get the size of the keyframebuffer uint16_t msglen = static_cast(kfBuffer.size()); + //the type of message uint16_t type = static_cast(network::datamessagestructures::PositionData); //create the full buffer