mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 13:12:39 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into brown
This commit is contained in:
commit
0a3c1712eb
21 changed files with 205 additions and 101 deletions
|
@ -2413,15 +2413,16 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
// Check HMD use (may be technically available without being in use)
|
||||
bool hasHMD = PluginUtils::isHMDAvailable();
|
||||
bool isUsingHMD = hasHMD && hasHandControllers && _displayPlugin->isHmd();
|
||||
bool isUsingHMD = _displayPlugin->isHmd();
|
||||
bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD;
|
||||
|
||||
Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false };
|
||||
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
|
||||
|
||||
bool isTutorialComplete = tutorialComplete.get();
|
||||
bool shouldGoToTutorial = isUsingHMD && hasTutorialContent && !isTutorialComplete;
|
||||
bool shouldGoToTutorial = isUsingHMDAndHandControllers && hasTutorialContent && !isTutorialComplete;
|
||||
|
||||
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMD;
|
||||
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers;
|
||||
qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent <<
|
||||
", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial;
|
||||
|
||||
|
@ -2435,10 +2436,18 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
const QString TUTORIAL_PATH = "/tutorial_begin";
|
||||
|
||||
static const QString SENT_TO_TUTORIAL = "tutorial";
|
||||
static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location";
|
||||
static const QString SENT_TO_ENTRY = "entry";
|
||||
static const QString SENT_TO_SANDBOX = "sandbox";
|
||||
|
||||
QString sentTo;
|
||||
|
||||
if (shouldGoToTutorial) {
|
||||
if (sandboxIsRunning) {
|
||||
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
|
||||
DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH);
|
||||
sentTo = SENT_TO_TUTORIAL;
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
|
||||
if (firstRun.get()) {
|
||||
|
@ -2446,8 +2455,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
}
|
||||
if (addressLookupString.isEmpty()) {
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
} else {
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
sentTo = SENT_TO_PREVIOUS_LOCATION;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2460,23 +2471,40 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
// If this is a first run we short-circuit the address passed in
|
||||
if (isFirstRun) {
|
||||
if (isUsingHMD) {
|
||||
if (isUsingHMDAndHandControllers) {
|
||||
if (sandboxIsRunning) {
|
||||
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
|
||||
DependencyManager::get<AddressManager>()->goToLocalSandbox();
|
||||
sentTo = SENT_TO_SANDBOX;
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
}
|
||||
} else {
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
}
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
sentTo = SENT_TO_PREVIOUS_LOCATION;
|
||||
}
|
||||
}
|
||||
|
||||
UserActivityLogger::getInstance().logAction("startup_sent_to", {
|
||||
{ "sent_to", sentTo },
|
||||
{ "sandbox_is_running", sandboxIsRunning },
|
||||
{ "has_hmd", hasHMD },
|
||||
{ "has_hand_controllers", hasHandControllers },
|
||||
{ "is_using_hmd", isUsingHMD },
|
||||
{ "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers },
|
||||
{ "content_version", contentVersion },
|
||||
{ "is_tutorial_complete", isTutorialComplete },
|
||||
{ "has_tutorial_content", hasTutorialContent },
|
||||
{ "should_go_to_tutorial", shouldGoToTutorial }
|
||||
});
|
||||
|
||||
_connectionMonitor.init();
|
||||
|
||||
// After all of the constructor is completed, then set firstRun to false.
|
||||
|
|
|
@ -407,6 +407,12 @@ Menu::Menu() {
|
|||
#endif
|
||||
|
||||
|
||||
{
|
||||
auto action = addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderClearKtxCache);
|
||||
connect(action, &QAction::triggered, []{
|
||||
Setting::Handle<int>(KTXCache::SETTING_VERSION_NAME, KTXCache::INVALID_VERSION).set(KTXCache::INVALID_VERSION);
|
||||
});
|
||||
}
|
||||
|
||||
// Developer > Render > LOD Tools
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0,
|
||||
|
|
|
@ -145,6 +145,7 @@ namespace MenuOption {
|
|||
const QString Quit = "Quit";
|
||||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
const QString ReloadContent = "Reload Content (Clears all caches)";
|
||||
const QString RenderClearKtxCache = "Clear KTX Cache (requires restart)";
|
||||
const QString RenderMaxTextureMemory = "Maximum Texture Memory";
|
||||
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
|
||||
const QString RenderMaxTexture4MB = "4 MB";
|
||||
|
|
|
@ -681,7 +681,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// and pretend that we own it (we assume we'll recover it soon)
|
||||
|
||||
// However, for now, when the server uses a newer time than what we sent, listen to what we're told.
|
||||
if (overwriteLocalData) weOwnSimulation = false;
|
||||
if (overwriteLocalData) {
|
||||
weOwnSimulation = false;
|
||||
}
|
||||
} else if (_simulationOwner.set(newSimOwner)) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
|
||||
somethingChanged = true;
|
||||
|
@ -1293,27 +1295,15 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
|
|||
properties._accelerationChanged = true;
|
||||
}
|
||||
|
||||
void EntityItem::pokeSimulationOwnership() {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE);
|
||||
void EntityItem::flagForOwnershipBid(uint8_t priority) {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
|
||||
// we already own it
|
||||
_simulationOwner.promotePriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
_simulationOwner.promotePriority(priority);
|
||||
} else {
|
||||
// we don't own it yet
|
||||
_simulationOwner.setPendingPriority(SCRIPT_POKE_SIMULATION_PRIORITY, usecTimestampNow());
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::grabSimulationOwnership() {
|
||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
|
||||
// we already own it
|
||||
_simulationOwner.promotePriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
} else {
|
||||
// we don't own it yet
|
||||
_simulationOwner.setPendingPriority(SCRIPT_GRAB_SIMULATION_PRIORITY, usecTimestampNow());
|
||||
_simulationOwner.setPendingPriority(priority, usecTimestampNow());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -321,6 +321,7 @@ public:
|
|||
void updateSimulationOwner(const SimulationOwner& owner);
|
||||
void clearSimulationOwnership();
|
||||
void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp);
|
||||
uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); }
|
||||
void rememberHasSimulationOwnershipBid() const;
|
||||
|
||||
QString getMarketplaceID() const;
|
||||
|
@ -394,8 +395,7 @@ public:
|
|||
|
||||
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
|
||||
|
||||
void pokeSimulationOwnership();
|
||||
void grabSimulationOwnership();
|
||||
void flagForOwnershipBid(uint8_t priority);
|
||||
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||
|
||||
QString actionsToDebugString();
|
||||
|
|
|
@ -230,6 +230,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
|
|||
}
|
||||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
// since we're creating this object we will immediately volunteer to own its simulation
|
||||
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
propertiesWithSimID.setLastEdited(entity->getLastEdited());
|
||||
} else {
|
||||
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
||||
|
@ -440,7 +442,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
} else {
|
||||
// we make a bid for simulation ownership
|
||||
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->pokeSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
entity->rememberHasSimulationOwnershipBid();
|
||||
}
|
||||
}
|
||||
|
@ -1194,7 +1196,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
|||
}
|
||||
action->setIsMine(true);
|
||||
success = entity->addAction(simulation, action);
|
||||
entity->grabSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
});
|
||||
if (success) {
|
||||
|
@ -1210,7 +1212,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
|
|||
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
|
||||
bool success = entity->updateAction(simulation, actionID, arguments);
|
||||
if (success) {
|
||||
entity->grabSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||
}
|
||||
return success;
|
||||
});
|
||||
|
@ -1224,7 +1226,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
|
|||
success = entity->removeAction(simulation, actionID);
|
||||
if (success) {
|
||||
// reduce from grab to poke
|
||||
entity->pokeSimulationOwnership();
|
||||
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||
}
|
||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||
});
|
||||
|
|
|
@ -26,12 +26,10 @@ namespace Simulation {
|
|||
const uint32_t DIRTY_MATERIAL = 0x00400;
|
||||
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
|
||||
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_POKE = 0x2000; // bid for simulation ownership at "poke"
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB = 0x4000; // bid for simulation ownership at "grab"
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
|
||||
|
||||
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
|
||||
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = DIRTY_SIMULATION_OWNERSHIP_FOR_POKE | DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB;
|
||||
};
|
||||
|
||||
#endif // hifi_SimulationFlags_h
|
||||
|
|
|
@ -26,9 +26,9 @@ const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1;
|
|||
SimulationOwner::SimulationOwner() :
|
||||
_id(),
|
||||
_expiry(0),
|
||||
_pendingTimestamp(0),
|
||||
_pendingBidTimestamp(0),
|
||||
_priority(0),
|
||||
_pendingPriority(0),
|
||||
_pendingBidPriority(0),
|
||||
_pendingState(PENDING_STATE_NOTHING)
|
||||
{
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ SimulationOwner::SimulationOwner() :
|
|||
SimulationOwner::SimulationOwner(const QUuid& id, quint8 priority) :
|
||||
_id(id),
|
||||
_expiry(0),
|
||||
_pendingTimestamp(0),
|
||||
_pendingBidTimestamp(0),
|
||||
_priority(priority),
|
||||
_pendingPriority(0)
|
||||
_pendingBidPriority(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,9 @@ bool SimulationOwner::fromByteArray(const QByteArray& data) {
|
|||
void SimulationOwner::clear() {
|
||||
_id = QUuid();
|
||||
_expiry = 0;
|
||||
_pendingTimestamp = 0;
|
||||
_pendingBidTimestamp = 0;
|
||||
_priority = 0;
|
||||
_pendingPriority = 0;
|
||||
_pendingBidPriority = 0;
|
||||
_pendingState = PENDING_STATE_NOTHING;
|
||||
}
|
||||
|
||||
|
@ -102,9 +102,9 @@ bool SimulationOwner::set(const SimulationOwner& owner) {
|
|||
}
|
||||
|
||||
void SimulationOwner::setPendingPriority(quint8 priority, const quint64& timestamp) {
|
||||
_pendingPriority = priority;
|
||||
_pendingTimestamp = timestamp;
|
||||
_pendingState = (_pendingPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
|
||||
_pendingBidPriority = priority;
|
||||
_pendingBidTimestamp = timestamp;
|
||||
_pendingState = (_pendingBidPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
|
||||
}
|
||||
|
||||
void SimulationOwner::updateExpiry() {
|
||||
|
@ -113,11 +113,11 @@ void SimulationOwner::updateExpiry() {
|
|||
}
|
||||
|
||||
bool SimulationOwner::pendingRelease(const quint64& timestamp) {
|
||||
return _pendingPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingTimestamp >= timestamp;
|
||||
return _pendingBidPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingBidTimestamp >= timestamp;
|
||||
}
|
||||
|
||||
bool SimulationOwner::pendingTake(const quint64& timestamp) {
|
||||
return _pendingPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingTimestamp >= timestamp;
|
||||
return _pendingBidPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingBidTimestamp >= timestamp;
|
||||
}
|
||||
|
||||
void SimulationOwner::clearCurrentOwner() {
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
|
||||
bool hasExpired() const { return usecTimestampNow() > _expiry; }
|
||||
|
||||
uint8_t getPendingPriority() const { return _pendingBidPriority; }
|
||||
bool pendingRelease(const quint64& timestamp); // return true if valid pending RELEASE
|
||||
bool pendingTake(const quint64& timestamp); // return true if valid pending TAKE
|
||||
void clearCurrentOwner();
|
||||
|
@ -84,9 +85,9 @@ public:
|
|||
private:
|
||||
QUuid _id; // owner
|
||||
quint64 _expiry; // time when ownership can transition at equal priority
|
||||
quint64 _pendingTimestamp; // time when pending update was set
|
||||
quint64 _pendingBidTimestamp; // time when pending bid was set
|
||||
quint8 _priority; // priority of current owner
|
||||
quint8 _pendingPriority; // priority of pendingTake
|
||||
quint8 _pendingBidPriority; // priority at which we'd like to own it
|
||||
quint8 _pendingState; // NOTHING, TAKE, or RELEASE
|
||||
};
|
||||
|
||||
|
|
|
@ -11,14 +11,28 @@
|
|||
|
||||
#include "KTXCache.h"
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <ktx/KTX.h>
|
||||
|
||||
using File = cache::File;
|
||||
using FilePointer = cache::FilePointer;
|
||||
|
||||
// Whenever a change is made to the serialized format for the KTX cache that isn't backward compatible,
|
||||
// this value should be incremented. This will force the KTX cache to be wiped
|
||||
const int KTXCache::CURRENT_VERSION = 0x01;
|
||||
const int KTXCache::INVALID_VERSION = 0x00;
|
||||
const char* KTXCache::SETTING_VERSION_NAME = "hifi.ktx.cache_version";
|
||||
|
||||
KTXCache::KTXCache(const std::string& dir, const std::string& ext) :
|
||||
FileCache(dir, ext) {
|
||||
initialize();
|
||||
|
||||
Setting::Handle<int> cacheVersionHandle(SETTING_VERSION_NAME, INVALID_VERSION);
|
||||
auto cacheVersion = cacheVersionHandle.get();
|
||||
if (cacheVersion != CURRENT_VERSION) {
|
||||
wipe();
|
||||
cacheVersionHandle.set(CURRENT_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
KTXFilePointer KTXCache::writeFile(const char* data, Metadata&& metadata) {
|
||||
|
|
|
@ -27,6 +27,12 @@ class KTXCache : public cache::FileCache {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Whenever a change is made to the serialized format for the KTX cache that isn't backward compatible,
|
||||
// this value should be incremented. This will force the KTX cache to be wiped
|
||||
static const int CURRENT_VERSION;
|
||||
static const int INVALID_VERSION;
|
||||
static const char* SETTING_VERSION_NAME;
|
||||
|
||||
KTXCache(const std::string& dir, const std::string& ext);
|
||||
|
||||
KTXFilePointer writeFile(const char* data, Metadata&& metadata);
|
||||
|
|
|
@ -236,6 +236,28 @@ namespace cache {
|
|||
};
|
||||
}
|
||||
|
||||
void FileCache::eject(const FilePointer& file) {
|
||||
file->_cache = nullptr;
|
||||
const auto& length = file->getLength();
|
||||
const auto& key = file->getKey();
|
||||
|
||||
{
|
||||
Lock lock(_filesMutex);
|
||||
if (0 != _files.erase(key)) {
|
||||
_numTotalFiles -= 1;
|
||||
_totalFilesSize -= length;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Lock unusedLock(_unusedFilesMutex);
|
||||
if (0 != _unusedFiles.erase(file)) {
|
||||
_numUnusedFiles -= 1;
|
||||
_unusedFilesSize -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::clean() {
|
||||
size_t overbudgetAmount = getOverbudgetAmount();
|
||||
|
||||
|
@ -250,28 +272,23 @@ void FileCache::clean() {
|
|||
for (const auto& file : _unusedFiles) {
|
||||
queue.push(file);
|
||||
}
|
||||
|
||||
while (!queue.empty() && overbudgetAmount > 0) {
|
||||
auto file = queue.top();
|
||||
queue.pop();
|
||||
eject(file);
|
||||
auto length = file->getLength();
|
||||
|
||||
unusedLock.unlock();
|
||||
{
|
||||
file->_cache = nullptr;
|
||||
Lock lock(_filesMutex);
|
||||
_files.erase(file->getKey());
|
||||
}
|
||||
unusedLock.lock();
|
||||
|
||||
_unusedFiles.erase(file);
|
||||
_numTotalFiles -= 1;
|
||||
_numUnusedFiles -= 1;
|
||||
_totalFilesSize -= length;
|
||||
_unusedFilesSize -= length;
|
||||
overbudgetAmount -= std::min(length, overbudgetAmount);
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::wipe() {
|
||||
Lock unusedFilesLock(_unusedFilesMutex);
|
||||
while (!_unusedFiles.empty()) {
|
||||
eject(*_unusedFiles.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::clear() {
|
||||
// Eliminate any overbudget files
|
||||
clean();
|
||||
|
|
|
@ -46,6 +46,9 @@ public:
|
|||
FileCache(const std::string& dirname, const std::string& ext, QObject* parent = nullptr);
|
||||
virtual ~FileCache();
|
||||
|
||||
// Remove all unlocked items from the cache
|
||||
void wipe();
|
||||
|
||||
size_t getNumTotalFiles() const { return _numTotalFiles; }
|
||||
size_t getNumCachedFiles() const { return _numUnusedFiles; }
|
||||
size_t getSizeTotalFiles() const { return _totalFilesSize; }
|
||||
|
@ -95,6 +98,9 @@ public:
|
|||
private:
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
using Map = std::unordered_map<Key, std::weak_ptr<File>>;
|
||||
using Set = std::unordered_set<FilePointer>;
|
||||
using KeySet = std::unordered_set<Key>;
|
||||
|
||||
friend class File;
|
||||
|
||||
|
@ -105,6 +111,8 @@ private:
|
|||
void removeUnusedFile(const FilePointer& file);
|
||||
void clean();
|
||||
void clear();
|
||||
// Remove a file from the cache
|
||||
void eject(const FilePointer& file);
|
||||
|
||||
size_t getOverbudgetAmount() const;
|
||||
|
||||
|
@ -122,10 +130,10 @@ private:
|
|||
std::string _dirpath;
|
||||
bool _initialized { false };
|
||||
|
||||
std::unordered_map<Key, std::weak_ptr<File>> _files;
|
||||
Map _files;
|
||||
Mutex _filesMutex;
|
||||
|
||||
std::unordered_set<FilePointer> _unusedFiles;
|
||||
Set _unusedFiles;
|
||||
Mutex _unusedFilesMutex;
|
||||
};
|
||||
|
||||
|
@ -136,8 +144,8 @@ public:
|
|||
using Key = FileCache::Key;
|
||||
using Metadata = FileCache::Metadata;
|
||||
|
||||
Key getKey() const { return _key; }
|
||||
size_t getLength() const { return _length; }
|
||||
const Key& getKey() const { return _key; }
|
||||
const size_t& getLength() const { return _length; }
|
||||
std::string getFilepath() const { return _filepath; }
|
||||
|
||||
virtual ~File();
|
||||
|
|
|
@ -65,8 +65,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
|||
_lastStep(0),
|
||||
_loopsWithoutOwner(0),
|
||||
_accelerationNearlyGravityCount(0),
|
||||
_numInactiveUpdates(1),
|
||||
_outgoingPriority(0)
|
||||
_numInactiveUpdates(1)
|
||||
{
|
||||
_type = MOTIONSTATE_TYPE_ENTITY;
|
||||
assert(_entity);
|
||||
|
@ -75,6 +74,8 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
|||
// we need the side-effects of EntityMotionState::setShape() so we call it explicitly here
|
||||
// rather than pass the legit shape pointer to the ObjectMotionState ctor above.
|
||||
setShape(shape);
|
||||
|
||||
_outgoingPriority = _entity->getPendingOwnershipPriority();
|
||||
}
|
||||
|
||||
EntityMotionState::~EntityMotionState() {
|
||||
|
@ -84,7 +85,7 @@ EntityMotionState::~EntityMotionState() {
|
|||
|
||||
void EntityMotionState::updateServerPhysicsVariables() {
|
||||
assert(entityTreeIsLocked());
|
||||
if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
|
||||
if (isLocallyOwned()) {
|
||||
// don't slam these values if we are the simulation owner
|
||||
return;
|
||||
}
|
||||
|
@ -136,23 +137,23 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
|
|||
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
|
||||
}
|
||||
_loopsWithoutOwner = 0;
|
||||
} else if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
|
||||
_numInactiveUpdates = 0;
|
||||
} else if (isLocallyOwned()) {
|
||||
// we just inherited ownership, make sure our desired priority matches what we have
|
||||
upgradeOutgoingPriority(_entity->getSimulationPriority());
|
||||
} else {
|
||||
_outgoingPriority = 0;
|
||||
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
|
||||
_numInactiveUpdates = 0;
|
||||
}
|
||||
}
|
||||
if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) {
|
||||
// The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bits really mean "we should bid for ownership because
|
||||
// a local script has been changing physics properties, or we should adjust our own ownership priority".
|
||||
// The desired priority is determined by which bits were set.
|
||||
if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB) {
|
||||
_outgoingPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||
} else {
|
||||
_outgoingPriority = SCRIPT_POKE_SIMULATION_PRIORITY;
|
||||
}
|
||||
// The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bit means one of the following:
|
||||
// (1) we own it but may need to change the priority OR...
|
||||
// (2) we don't own it but should bid (because a local script has been changing physics properties)
|
||||
uint8_t newPriority = isLocallyOwned() ? _entity->getSimulationOwner().getPriority() : _entity->getSimulationOwner().getPendingPriority();
|
||||
_outgoingPriority = glm::max(_outgoingPriority, newPriority);
|
||||
|
||||
// reset bid expiry so that we bid ASAP
|
||||
_nextOwnershipBid = 0;
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ bool EntityMotionState::isCandidateForOwnership() const {
|
|||
assert(_entity);
|
||||
assert(entityTreeIsLocked());
|
||||
return _outgoingPriority != 0
|
||||
|| Physics::getSessionUUID() == _entity->getSimulatorID()
|
||||
|| isLocallyOwned()
|
||||
|| _entity->dynamicDataNeedsTransmit();
|
||||
}
|
||||
|
||||
|
@ -491,7 +492,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_entity->getSimulatorID() != Physics::getSessionUUID()) {
|
||||
if (!isLocallyOwned()) {
|
||||
// we don't own the simulation
|
||||
|
||||
// NOTE: we do not volunteer to own kinematic or static objects
|
||||
|
@ -599,7 +600,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
properties.clearSimulationOwner();
|
||||
_outgoingPriority = 0;
|
||||
_entity->setPendingOwnershipPriority(_outgoingPriority, now);
|
||||
} else if (Physics::getSessionUUID() != _entity->getSimulatorID()) {
|
||||
} else if (!isLocallyOwned()) {
|
||||
// we don't own the simulation for this entity yet, but we're sending a bid for it
|
||||
quint8 bidPriority = glm::max<uint8_t>(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY);
|
||||
properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority);
|
||||
|
@ -788,6 +789,10 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma
|
|||
_entity->computeCollisionGroupAndFinalMask(group, mask);
|
||||
}
|
||||
|
||||
bool EntityMotionState::isLocallyOwned() const {
|
||||
return _entity->getSimulatorID() == Physics::getSessionUUID();
|
||||
}
|
||||
|
||||
bool EntityMotionState::shouldBeLocallyOwned() const {
|
||||
return (_outgoingPriority > VOLUNTEER_SIMULATION_PRIORITY && _outgoingPriority > _entity->getSimulationPriority()) ||
|
||||
_entity->getSimulatorID() == Physics::getSessionUUID();
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
|
||||
virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override;
|
||||
|
||||
bool isLocallyOwned() const override;
|
||||
bool shouldBeLocallyOwned() const override;
|
||||
|
||||
friend class PhysicalEntitySimulation;
|
||||
|
|
|
@ -146,6 +146,7 @@ public:
|
|||
void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; }
|
||||
void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; }
|
||||
|
||||
virtual bool isLocallyOwned() const { return false; }
|
||||
virtual bool shouldBeLocallyOwned() const { return false; }
|
||||
|
||||
friend class PhysicsEngine;
|
||||
|
|
|
@ -129,6 +129,9 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
|
|||
}
|
||||
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||
body->updateInertiaTensor();
|
||||
if (motionState->isLocallyOwned()) {
|
||||
_activeStaticBodies.insert(body);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -174,19 +177,9 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
|
|||
// frame (because the framerate is faster than our physics simulation rate). When this happens we must scan
|
||||
// _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer.
|
||||
for (auto object : objects) {
|
||||
btRigidBody* body = object->getRigidBody();
|
||||
|
||||
std::vector<btRigidBody*>::reverse_iterator itr = _activeStaticBodies.rbegin();
|
||||
while (itr != _activeStaticBodies.rend()) {
|
||||
if (body == *itr) {
|
||||
if (*itr != *(_activeStaticBodies.rbegin())) {
|
||||
// swap with rbegin
|
||||
*itr = *(_activeStaticBodies.rbegin());
|
||||
}
|
||||
_activeStaticBodies.pop_back();
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
std::set<btRigidBody*>::iterator itr = _activeStaticBodies.find(object->getRigidBody());
|
||||
if (itr != _activeStaticBodies.end()) {
|
||||
_activeStaticBodies.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,14 +238,16 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob
|
|||
object->clearIncomingDirtyFlags();
|
||||
}
|
||||
if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) {
|
||||
_activeStaticBodies.push_back(object->getRigidBody());
|
||||
_activeStaticBodies.insert(object->getRigidBody());
|
||||
}
|
||||
}
|
||||
// active static bodies have changed (in an Easy way) and need their Aabbs updated
|
||||
// but we've configured Bullet to NOT update them automatically (for improved performance)
|
||||
// so we must do it ourselves
|
||||
for (size_t i = 0; i < _activeStaticBodies.size(); ++i) {
|
||||
_dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]);
|
||||
std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
|
||||
while (itr != _activeStaticBodies.end()) {
|
||||
_dynamicsWorld->updateSingleAabb(*itr);
|
||||
++itr;
|
||||
}
|
||||
return stillNeedChange;
|
||||
}
|
||||
|
@ -496,13 +491,23 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
|
|||
|
||||
const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() {
|
||||
BT_PROFILE("copyOutgoingChanges");
|
||||
|
||||
_dynamicsWorld->synchronizeMotionStates();
|
||||
|
||||
// Bullet will not deactivate static objects (it doesn't expect them to be active)
|
||||
// so we must deactivate them ourselves
|
||||
for (size_t i = 0; i < _activeStaticBodies.size(); ++i) {
|
||||
_activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING);
|
||||
std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
|
||||
while (itr != _activeStaticBodies.end()) {
|
||||
btRigidBody* body = *itr;
|
||||
body->forceActivationState(ISLAND_SLEEPING);
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(body->getUserPointer());
|
||||
if (motionState) {
|
||||
_dynamicsWorld->addChangedMotionState(motionState);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
_activeStaticBodies.clear();
|
||||
_dynamicsWorld->synchronizeMotionStates();
|
||||
|
||||
_hasOutgoingChanges = false;
|
||||
return _dynamicsWorld->getChangedMotionStates();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_PhysicsEngine_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <QUuid>
|
||||
|
@ -114,7 +115,7 @@ private:
|
|||
CollisionEvents _collisionEvents;
|
||||
QHash<QUuid, EntityDynamicPointer> _objectDynamics;
|
||||
QHash<btRigidBody*, QSet<QUuid>> _objectDynamicsByBody;
|
||||
std::vector<btRigidBody*> _activeStaticBodies;
|
||||
std::set<btRigidBody*> _activeStaticBodies;
|
||||
|
||||
glm::vec3 _originOffset;
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ public:
|
|||
const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; }
|
||||
const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; }
|
||||
|
||||
void addChangedMotionState(ObjectMotionState* motionState) { _changedMotionStates.push_back(motionState); }
|
||||
|
||||
private:
|
||||
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
|
||||
void synchronizeMotionState(btRigidBody* body);
|
||||
|
|
|
@ -113,18 +113,21 @@ void FileCacheTests::testUnusedFiles() {
|
|||
QVERIFY(!file.get());
|
||||
}
|
||||
|
||||
QThread::msleep(1000);
|
||||
// Test files 90 to 99 are present
|
||||
for (int i = 90; i < 100; ++i) {
|
||||
std::string key = getFileKey(i);
|
||||
auto file = cache->getFile(key);
|
||||
QVERIFY(file.get());
|
||||
inUseFiles.push_back(file);
|
||||
// Each access touches the file, so we need to sleep here to ensure that the files are
|
||||
// spaced out in numeric order, otherwise later tests can't reliably determine the order
|
||||
// for cache ejection
|
||||
QThread::msleep(1000);
|
||||
|
||||
if (i == 94) {
|
||||
// Each access touches the file, so we need to sleep here to ensure that the the last 5 files
|
||||
// have later times for cache ejection priority, otherwise the test runs too fast to reliably
|
||||
// differentiate
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)10);
|
||||
inUseFiles.clear();
|
||||
|
@ -165,6 +168,20 @@ void FileCacheTests::testFreeSpacePreservation() {
|
|||
}
|
||||
}
|
||||
|
||||
void FileCacheTests::testWipe() {
|
||||
// Reset the cache
|
||||
auto cache = makeFileCache(_testDir.path());
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)5);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)5);
|
||||
cache->wipe();
|
||||
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
|
||||
QCOMPARE(cache->getNumTotalFiles(), (size_t)0);
|
||||
QVERIFY(getCacheDirectorySize() > 0);
|
||||
forceDeletes();
|
||||
QCOMPARE(getCacheDirectorySize(), (size_t)0);
|
||||
}
|
||||
|
||||
|
||||
void FileCacheTests::cleanupTestCase() {
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ private slots:
|
|||
void testUnusedFiles();
|
||||
void testFreeSpacePreservation();
|
||||
void cleanupTestCase();
|
||||
void testWipe();
|
||||
|
||||
private:
|
||||
size_t getFreeSpace() const;
|
||||
|
|
Loading…
Reference in a new issue