mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-18 21:17:41 +02:00
merge master
This commit is contained in:
commit
7c7c3cd223
79 changed files with 947 additions and 249 deletions
|
@ -84,7 +84,7 @@ Agent::Agent(ReceivedMessage& message) :
|
|||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<PluginManager>();
|
||||
DependencyManager::set<PluginManager>()->instantiate();
|
||||
|
||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||
|
||||
|
@ -511,6 +511,7 @@ void Agent::executeScript() {
|
|||
|
||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
||||
|
||||
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_scriptEngine);
|
||||
_scriptEngine->run();
|
||||
|
||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <HifiConfigVariantMap.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <shared/ScriptInitializerMixin.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
|
@ -240,6 +241,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
QThread::currentThread()->setObjectName("main thread");
|
||||
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::set<ScriptInitializers>();
|
||||
|
||||
if (numForks || minForks || maxForks) {
|
||||
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
||||
|
|
|
@ -499,6 +499,8 @@ void AvatarMixer::handleAvatarKilled(SharedNodePointer avatarNode) {
|
|||
} else {
|
||||
_sessionDisplayNames.erase(displayNameIter);
|
||||
}
|
||||
|
||||
nodeData->getAvatar().stopChallengeTimer();
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacket> killPacket;
|
||||
|
|
|
@ -332,7 +332,7 @@ void MixerAvatar::sendOwnerChallenge() {
|
|||
void MixerAvatar::processChallengeResponse(ReceivedMessage& response) {
|
||||
QByteArray avatarID;
|
||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||
QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop);
|
||||
stopChallengeTimer();
|
||||
if (_verifyState == challengeClient) {
|
||||
QByteArray responseData = response.readAll();
|
||||
if (responseData.length() < 8) {
|
||||
|
@ -365,3 +365,11 @@ void MixerAvatar::processChallengeResponse(ReceivedMessage& response) {
|
|||
qCDebug(avatars) << "WARNING: Unexpected avatar challenge-response in state" << stateToName(_verifyState);
|
||||
}
|
||||
}
|
||||
|
||||
void MixerAvatar::stopChallengeTimer() {
|
||||
if (QThread::currentThread() == thread()) {
|
||||
_challengeTimer.stop();
|
||||
} else {
|
||||
QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ public:
|
|||
void processCertifyEvents();
|
||||
void processChallengeResponse(ReceivedMessage& response);
|
||||
|
||||
void stopChallengeTimer();
|
||||
|
||||
// Avatar certification/verification:
|
||||
enum VerifyState {
|
||||
nonCertified, requestingFST, receivedFST, staticValidation, requestingOwner, ownerResponse,
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#include <QJsonDocument>
|
||||
|
||||
#include <EntityTree.h>
|
||||
#include <SimpleEntitySimulation.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <EntityEditFilters.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <hfm/ModelFormatRegistry.h>
|
||||
|
@ -36,12 +36,13 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
|
|||
|
||||
EntityServer::EntityServer(ReceivedMessage& message) :
|
||||
OctreeServer(message),
|
||||
_entitySimulation(NULL),
|
||||
_entitySimulation(nullptr),
|
||||
_dynamicDomainVerificationTimer(this)
|
||||
{
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<ScriptCache>();
|
||||
DependencyManager::set<PluginManager>()->instantiate();
|
||||
|
||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
||||
DependencyManager::set<AssignmentDynamicFactory>();
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include <EntityItem.h>
|
||||
#include <EntityTree.h>
|
||||
#include <SimpleEntitySimulation.h>
|
||||
|
||||
#include "EntityServerConsts.h"
|
||||
#include "EntityTree.h"
|
||||
|
||||
/// Handles assignments of type EntityServer - sending entities to various clients.
|
||||
|
||||
|
@ -27,9 +29,6 @@ struct ViewerSendingStats {
|
|||
quint64 lastEdited;
|
||||
};
|
||||
|
||||
class SimpleEntitySimulation;
|
||||
using SimpleEntitySimulationPointer = std::shared_ptr<SimpleEntitySimulation>;
|
||||
|
||||
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
|
@ -64,7 +64,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
|||
DependencyManager::set<ResourceScriptingInterface>();
|
||||
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<PluginManager>();
|
||||
DependencyManager::set<PluginManager>()->instantiate();
|
||||
|
||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||
|
||||
|
@ -301,10 +301,17 @@ void EntityScriptServer::run() {
|
|||
|
||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||
|
||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
||||
auto treePtr = _entityViewer.getTree();
|
||||
DependencyManager::set<AssignmentParentFinder>(treePtr);
|
||||
|
||||
if (!_entitySimulation) {
|
||||
SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
|
||||
simpleSimulation->setEntityTree(treePtr);
|
||||
treePtr->setSimulation(simpleSimulation);
|
||||
_entitySimulation = simpleSimulation;
|
||||
}
|
||||
|
||||
auto tree = _entityViewer.getTree().get();
|
||||
auto tree = treePtr.get();
|
||||
connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
|
||||
connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
|
||||
connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
|
||||
|
@ -451,10 +458,11 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
|||
|
||||
connect(newEngine.data(), &ScriptEngine::update, this, [this] {
|
||||
_entityViewer.queryOctree();
|
||||
_entityViewer.getTree()->preUpdate();
|
||||
_entityViewer.getTree()->update();
|
||||
});
|
||||
|
||||
|
||||
scriptEngines->runScriptInitializers(newEngine);
|
||||
newEngine->runInThread();
|
||||
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <EntityEditPacketSender.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <SimpleEntitySimulation.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
#include "../entities/EntityTreeHeadlessViewer.h"
|
||||
|
||||
|
@ -75,6 +76,7 @@ private:
|
|||
|
||||
static int _entitiesScriptEngineCount;
|
||||
ScriptEnginePointer _entitiesScriptEngine;
|
||||
SimpleEntitySimulationPointer _entitySimulation;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
EntityTreeHeadlessViewer _entityViewer;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(BUILD_ORGANIZATION "High Fidelity")
|
||||
set(HIGH_FIDELITY_PROTOCOL "hifi")
|
||||
set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp")
|
||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
||||
set(INTERFACE_BUNDLE_NAME "interface")
|
||||
set(INTERFACE_ICON_PREFIX "interface")
|
||||
|
||||
# add definition for this release type
|
||||
|
@ -61,7 +61,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(PR_BUILD 1)
|
||||
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
|
||||
set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}")
|
||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
||||
set(INTERFACE_BUNDLE_NAME "interface")
|
||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||
|
||||
# add definition for this release type
|
||||
|
@ -70,7 +70,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(DEV_BUILD 1)
|
||||
set(BUILD_VERSION "dev")
|
||||
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
||||
set(INTERFACE_BUNDLE_NAME "interface")
|
||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||
|
||||
# add definition for this release type
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
#
|
||||
macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
|
||||
set(${TARGET_NAME}_SHARED 1)
|
||||
setup_hifi_library(${ARGV})
|
||||
set(PLUGIN_SUBFOLDER ${ARGN})
|
||||
setup_hifi_library()
|
||||
|
||||
if (BUILD_CLIENT)
|
||||
add_dependencies(interface ${TARGET_NAME})
|
||||
|
@ -27,6 +28,11 @@ macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
|
|||
set(SERVER_PLUGIN_PATH "plugins")
|
||||
endif()
|
||||
|
||||
if (PLUGIN_SUBFOLDER)
|
||||
set(CLIENT_PLUGIN_PATH "${CLIENT_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}")
|
||||
set(SERVER_PLUGIN_PATH "${SERVER_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}")
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||
set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/")
|
||||
set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/")
|
||||
|
|
|
@ -1156,7 +1156,17 @@ FunctionEnd
|
|||
|
||||
Section "-Core installation"
|
||||
|
||||
;The following delete blocks are temporary and can be removed once users who had the initial installer have updated
|
||||
; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated
|
||||
; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are.
|
||||
|
||||
; MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@"
|
||||
|
||||
;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer
|
||||
${If} "@INSTALLER_TYPE@" == "client_only"
|
||||
; MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries"
|
||||
Delete "$INSTDIR\assignment-client.exe"
|
||||
Delete "$INSTDIR\domain-server.exe"
|
||||
${EndIf}
|
||||
|
||||
;Delete any server-console files installed before it was placed in sub-folder
|
||||
Delete "$INSTDIR\server-console.exe"
|
||||
|
|
20
interface/interface.entitlements
Normal file
20
interface/interface.entitlements
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>high-fidelity.hifi</string>
|
||||
</array>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -824,6 +824,19 @@
|
|||
},
|
||||
"id": "seatedReactionPositiveCheer",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 64,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_agree_acknowledge.fbx"
|
||||
},
|
||||
"id": "seatedReactionPositiveAcknowledge",
|
||||
"type": "clip"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
|
@ -869,6 +882,15 @@
|
|||
"resume": false,
|
||||
"transitions": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "seatedReactionPositiveAcknowledge",
|
||||
"interpDuration": 1,
|
||||
"interpTarget": 1,
|
||||
"priority": 1,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
]
|
||||
}
|
||||
],
|
||||
"timeScale": 1,
|
||||
|
@ -918,6 +940,19 @@
|
|||
},
|
||||
"id": "seatedReactionNegativeDisagreeDisbelief",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 70,
|
||||
"loopFlag": false,
|
||||
"startFrame": 0,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_disagree_dismiss.fbx"
|
||||
},
|
||||
"id": "seatedReactionNegativeDisagreeDismiss",
|
||||
"type": "clip"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
|
@ -960,6 +995,17 @@
|
|||
"resume": false,
|
||||
"transitions": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionNegativeDisagreeDismiss",
|
||||
"interpDuration": 1,
|
||||
"interpTarget": 1,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 1,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
]
|
||||
}
|
||||
],
|
||||
"timeScale": 1,
|
||||
|
@ -1048,6 +1094,47 @@
|
|||
},
|
||||
"id": "seatedReactionRaiseHand02Outro",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 15,
|
||||
"loopFlag": false,
|
||||
"startFrame": 0,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_raisehand03_all.fbx"
|
||||
},
|
||||
"id": "seatedReactionRaiseHand03Intro",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 233,
|
||||
"loopFlag": true,
|
||||
"mirrorFlag": false,
|
||||
"startFrame": 15,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_raisehand03_all.fbx"
|
||||
},
|
||||
"id": "seatedReactionRaiseHand03Loop",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 296,
|
||||
"loopFlag": false,
|
||||
"mirrorFlag": false,
|
||||
"startFrame": 233,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_raisehand03_all.fbx"
|
||||
},
|
||||
"id": "seatedReactionRaiseHand03Outro",
|
||||
"type": "clip"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
|
@ -1059,7 +1146,7 @@
|
|||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionRaiseHandIntro",
|
||||
"interpDuration": 8,
|
||||
"interpTarget": 8,
|
||||
"interpTarget": 9,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 1,
|
||||
"resume": false,
|
||||
|
@ -1140,6 +1227,49 @@
|
|||
"var": "reactionRaiseHandEnabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionRaiseHand03Intro",
|
||||
"interpDuration": 8,
|
||||
"interpTarget": 8,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 1,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
{
|
||||
"randomSwitchState": "seatedReactionRaiseHand03Loop",
|
||||
"var": "seatedReactionRaiseHand03IntroOnDone"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "seatedReactionRaiseHand03Loop",
|
||||
"interpDuration": 1,
|
||||
"interpTarget": 1,
|
||||
"priority": 0,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
{
|
||||
"randomSwitchState": "seatedReactionRaiseHand03Outro",
|
||||
"var": "reactionRaiseHandDisabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionRaiseHand03Outro",
|
||||
"interpDuration": 12,
|
||||
"interpTarget": 12,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 0,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
{
|
||||
"randomSwitchState": "seatedReactionRaiseHand03Loop",
|
||||
"var": "reactionRaiseHandEnabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"triggerRandomSwitch": ""
|
||||
|
@ -1226,6 +1356,45 @@
|
|||
},
|
||||
"id": "seatedReactionApplaud02Outro",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 17,
|
||||
"loopFlag": false,
|
||||
"startFrame": 0,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_clap03_all.fbx"
|
||||
},
|
||||
"id": "seatedReactionApplaud03Intro",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 111,
|
||||
"loopFlag": true,
|
||||
"startFrame": 17,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_clap03_all.fbx"
|
||||
},
|
||||
"id": "seatedReactionApplaud03Loop",
|
||||
"type": "clip"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 136,
|
||||
"loopFlag": false,
|
||||
"startFrame": 111,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_clap03_all.fbx"
|
||||
},
|
||||
"id": "seatedReactionApplaud03Outro",
|
||||
"type": "clip"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
|
@ -1322,6 +1491,51 @@
|
|||
"var": "reactionApplaudEnabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionApplaud03Intro",
|
||||
"interpDuration": 8,
|
||||
"interpTarget": 8,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 1,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
{
|
||||
"randomSwitchState": "seatedReactionApplaud03Loop",
|
||||
"var": "seatedReactionApplaud03IntroOnDone"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionApplaud03Loop",
|
||||
"interpDuration": 1,
|
||||
"interpTarget": 1,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 0,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
{
|
||||
"randomSwitchState": "seatedReactionApplaud03Outro",
|
||||
"var": "reactionApplaudDisabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "seatedReactionApplaud03Outro",
|
||||
"interpDuration": 12,
|
||||
"interpTarget": 12,
|
||||
"interpType": "evaluateBoth",
|
||||
"priority": 0,
|
||||
"resume": false,
|
||||
"transitions": [
|
||||
{
|
||||
"randomSwitchState": "seatedReactionApplaud03Loop",
|
||||
"var": "reactionApplaudEnabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"triggerRandomSwitch": ""
|
||||
|
@ -1335,7 +1549,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 22,
|
||||
"endFrame": 21,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -1348,9 +1562,9 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 43,
|
||||
"endFrame": 100,
|
||||
"loopFlag": true,
|
||||
"startFrame": 22,
|
||||
"startFrame": 21,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
|
||||
},
|
||||
|
@ -1361,9 +1575,10 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 71,
|
||||
"endFrame": 134,
|
||||
"loopFlag": false,
|
||||
"startFrame": 43,
|
||||
"mirrorFlag": false,
|
||||
"startFrame": 100,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
|
||||
},
|
||||
|
@ -1483,6 +1698,10 @@
|
|||
"state": "seatedTalkOverlay",
|
||||
"var": "seatedReactionPositiveCheerOnDone"
|
||||
},
|
||||
{
|
||||
"state": "seatedTalkOverlay",
|
||||
"var": "seatedReactionPositiveAcknowledgeOnDone"
|
||||
},
|
||||
{
|
||||
"state": "seatedReactionNegative",
|
||||
"var": "reactionNegativeTrigger"
|
||||
|
@ -1524,6 +1743,10 @@
|
|||
"state": "seatedTalkOverlay",
|
||||
"var": "seatedReactionNegativeDisagreeDisbeliefOnDone"
|
||||
},
|
||||
{
|
||||
"state": "seatedTalkOverlay",
|
||||
"var": "seatedReactionNegativeDisagreeDismissOnDone"
|
||||
},
|
||||
{
|
||||
"state": "seatedReactionRaiseHand",
|
||||
"var": "reactionRaiseHandEnabled"
|
||||
|
@ -2432,7 +2655,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 58,
|
||||
"endFrame": 64,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -2458,7 +2681,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 78,
|
||||
"endFrame": 94,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -2471,7 +2694,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 66,
|
||||
"endFrame": 68,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -2484,7 +2707,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 85,
|
||||
"endFrame": 84,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -2981,7 +3204,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 18,
|
||||
"endFrame": 17,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -2994,9 +3217,9 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 97,
|
||||
"endFrame": 111,
|
||||
"loopFlag": true,
|
||||
"startFrame": 18,
|
||||
"startFrame": 17,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/emote_clap01_all.fbx"
|
||||
},
|
||||
|
@ -3007,9 +3230,9 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 146,
|
||||
"endFrame": 160,
|
||||
"loopFlag": false,
|
||||
"startFrame": 97,
|
||||
"startFrame": 111,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/emote_clap01_all.fbx"
|
||||
},
|
||||
|
@ -3310,7 +3533,7 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 22,
|
||||
"endFrame": 21,
|
||||
"loopFlag": false,
|
||||
"startFrame": 1,
|
||||
"timeScale": 1,
|
||||
|
@ -3323,9 +3546,9 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 40,
|
||||
"endFrame": 100,
|
||||
"loopFlag": true,
|
||||
"startFrame": 22,
|
||||
"startFrame": 21,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
|
||||
},
|
||||
|
@ -3336,9 +3559,9 @@
|
|||
"children": [
|
||||
],
|
||||
"data": {
|
||||
"endFrame": 78,
|
||||
"endFrame": 134,
|
||||
"loopFlag": false,
|
||||
"startFrame": 40,
|
||||
"startFrame": 100,
|
||||
"timeScale": 1,
|
||||
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
|
||||
},
|
||||
|
@ -3407,8 +3630,8 @@
|
|||
{
|
||||
"easingType": "easeInOutQuad",
|
||||
"id": "idleTalkOverlay",
|
||||
"interpDuration": 24,
|
||||
"interpTarget": 24,
|
||||
"interpDuration": 20,
|
||||
"interpTarget": 20,
|
||||
"interpType": "evaluateBoth",
|
||||
"transitions": [
|
||||
{
|
||||
|
@ -5648,4 +5871,4 @@
|
|||
"type": "blendLinear"
|
||||
},
|
||||
"version": "1.1"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Copyright 2016 High Fidelity, Inc. -->
|
||||
<!-- Copyright 2016 High Fidelity, Inc. -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
|
@ -77,9 +77,9 @@
|
|||
var handControllerImageURL = null;
|
||||
var index = 0;
|
||||
var count = 3;
|
||||
var handControllerRefURL = "https://docs.highfidelity.com/en/rc81/explore/get-started/vr-controls.html#vr-controls";
|
||||
var keyboardRefURL = "https://docs.highfidelity.com/en/rc81/explore/get-started/desktop.html#movement-controls";
|
||||
var gamepadRefURL = "https://docs.highfidelity.com/en/rc81/explore/get-started/vr-controls.html#gamepad";
|
||||
var handControllerRefURL = "https://docs.highfidelity.com/explore/get-started/vr-controls.html#vr-controls";
|
||||
var keyboardRefURL = "https://docs.highfidelity.com/explore/get-started/desktop.html#movement-controls";
|
||||
var gamepadRefURL = "https://docs.highfidelity.com/explore/get-started/vr-controls.html#gamepad";
|
||||
|
||||
function showKbm() {
|
||||
document.getElementById("main_image").setAttribute("src", "img/tablet-help-keyboard.jpg");
|
||||
|
|
|
@ -240,9 +240,96 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
// -- Plugin Permissions --
|
||||
Item {
|
||||
id: kpiContainer;
|
||||
anchors.top: accountContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: childrenRect.height;
|
||||
|
||||
Rectangle {
|
||||
id: kpiHeaderContainer;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 55;
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
text: "Plugin Permissions";
|
||||
anchors.fill: parent;
|
||||
anchors.leftMargin: 20;
|
||||
color: hifi.colors.white;
|
||||
size: 18;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: kpiScriptContainer;
|
||||
anchors.top: kpiHeaderContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 80;
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: kpiScriptCheckbox;
|
||||
readonly property string kpiSettingsKey: "private/enableScriptingPlugins"
|
||||
checked: Settings.getValue(kpiSettingsKey, false);
|
||||
text: "Enable custom script plugins (requires restart)"
|
||||
// Anchors
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
boxSize: 24;
|
||||
labelFontSize: 18;
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
color: hifi.colors.white;
|
||||
width: 300;
|
||||
onCheckedChanged: Settings.setValue(kpiSettingsKey, checked);
|
||||
}
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
id: kpiScriptHelp;
|
||||
text: '[?]';
|
||||
// Anchors
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: kpiScriptCheckbox.right;
|
||||
width: 30;
|
||||
height: 30;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueHighlight;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
onEntered: {
|
||||
parent.color = hifi.colors.blueAccent;
|
||||
}
|
||||
onExited: {
|
||||
parent.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onClicked: {
|
||||
lightboxPopup.titleText = "Script Plugin Infrastructure by Kasen";
|
||||
lightboxPopup.bodyText = "Toggles the activation of scripting plugins in the 'plugins/scripting' folder. \n\n"
|
||||
+ "Created by https://kasen.io/";
|
||||
lightboxPopup.button1text = "OK";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
id: walletContainer;
|
||||
anchors.top: accountContainer.bottom;
|
||||
anchors.top: kpiContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: childrenRect.height;
|
||||
|
|
|
@ -167,7 +167,7 @@ Flickable {
|
|||
Component.onCompleted: {
|
||||
var cpu = JSON.parse(PlatformInfo.getCPU(0));
|
||||
var cpuModel = cpu.model;
|
||||
if (cpuModel.length === 0) {
|
||||
if (!cpuModel || cpuModel.length === 0) {
|
||||
cpuModel = "Unknown";
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@ Flickable {
|
|||
Component.onCompleted: {
|
||||
var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU()));
|
||||
var gpuModel = gpu.model;
|
||||
if (gpuModel.length === 0) {
|
||||
if (!gpuModel || gpuModel.length === 0) {
|
||||
gpuModel = "Unknown";
|
||||
}
|
||||
|
||||
|
@ -327,7 +327,7 @@ Flickable {
|
|||
|
||||
var cpu = JSON.parse(PlatformInfo.getCPU(0));
|
||||
var cpuModel = cpu.model;
|
||||
if (cpuModel.length === 0) {
|
||||
if (!cpuModel || cpuModel.length === 0) {
|
||||
cpuModel = "Unknown";
|
||||
}
|
||||
|
||||
|
@ -338,7 +338,7 @@ Flickable {
|
|||
|
||||
var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU()));
|
||||
var gpuModel = gpu.model;
|
||||
if (gpuModel.length === 0) {
|
||||
if (!gpuModel || gpuModel.length === 0) {
|
||||
gpuModel = "Unknown";
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,8 @@ TextField {
|
|||
leftPadding: 0
|
||||
rightPadding: root.rightGlyph === "" ? 0 : rightGlyphItem.implicitWidth + simplifiedUI.sizes.controls.textField.rightGlyphPadding
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
onPressed: {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
onHoveredChanged: {
|
||||
|
|
|
@ -811,6 +811,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
}
|
||||
|
||||
// Tell the plugin manager about our statically linked plugins
|
||||
DependencyManager::set<ScriptInitializers>();
|
||||
DependencyManager::set<PluginManager>();
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
||||
|
@ -860,7 +861,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
#endif
|
||||
DependencyManager::set<StatTracker>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption);
|
||||
DependencyManager::set<ScriptInitializerMixin, NativeScriptInitializers>();
|
||||
DependencyManager::set<Preferences>();
|
||||
DependencyManager::set<recording::Deck>();
|
||||
DependencyManager::set<recording::Recorder>();
|
||||
|
@ -3429,7 +3429,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext));
|
||||
surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
|
||||
surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data());
|
||||
|
@ -3545,7 +3545,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
|
|||
surfaceContext->setContextProperty("offscreenFlags", flags);
|
||||
surfaceContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
|
||||
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext));
|
||||
surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("Performance", new PerformanceScriptingInterface());
|
||||
|
||||
|
|
|
@ -313,8 +313,8 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
if (spine2Joint >= 0) {
|
||||
params.spine2ShapeInfo = hfmModel.joints[spine2Joint].shapeInfo;
|
||||
}
|
||||
|
||||
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
||||
const float TALKING_TIME_THRESHOLD = 0.75f;
|
||||
params.isTalking = head->getTimeWithoutTalking() <= TALKING_TIME_THRESHOLD;
|
||||
|
||||
myAvatar->updateRigControllerParameters(params);
|
||||
|
||||
|
|
|
@ -512,13 +512,13 @@ void OtherAvatar::handleChangedAvatarEntityData() {
|
|||
entity->setParentID(NULL_ID);
|
||||
entity->setParentID(oldParentID);
|
||||
|
||||
if (entity->stillHasMyGrabAction()) {
|
||||
if (entity->stillHasMyGrab()) {
|
||||
// For this case: we want to ignore transform+velocities coming from authoritative OtherAvatar
|
||||
// because the MyAvatar is grabbing and we expect the local grab state
|
||||
// to have enough information to prevent simulation drift.
|
||||
//
|
||||
// Clever readers might realize this could cause problems. For example,
|
||||
// if an ignored OtherAvagtar were to simultanously grab the object then there would be
|
||||
// if an ignored OtherAvatar were to simultanously grab the object then there would be
|
||||
// a noticeable discrepancy between participants in the distributed physics simulation,
|
||||
// however the difference would be stable and would not drift.
|
||||
properties.clearTransformOrVelocityChanges();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <QtCore/QProcess>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLocalSocket>
|
||||
#include <QLocalServer>
|
||||
#include <QSharedMemory>
|
||||
|
@ -117,21 +118,27 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
|
||||
QString applicationPath;
|
||||
// A temporary application instance is needed to get the location of the running executable
|
||||
// Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV)
|
||||
// If we wanted to avoid the QCoreApplication, we would need to write our own
|
||||
// cross-platform implementation.
|
||||
{
|
||||
// A temporary application instance is needed to get the location of the running executable
|
||||
// Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV)
|
||||
// If we wanted to avoid the QCoreApplication, we would need to write our own
|
||||
// cross-platform implementation.
|
||||
QCoreApplication tempApp(argc, const_cast<char**>(argv));
|
||||
#ifdef Q_OS_OSX
|
||||
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) {
|
||||
applicationPath = QCoreApplication::applicationDirPath() + "/../../../";
|
||||
} else {
|
||||
applicationPath = QCoreApplication::applicationDirPath();
|
||||
}
|
||||
#else
|
||||
applicationPath = QCoreApplication::applicationDirPath();
|
||||
#endif
|
||||
}
|
||||
|
||||
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
|
||||
QDir applicationDir(applicationPath);
|
||||
QString configFileName = applicationDir.filePath(APPLICATION_CONFIG_FILENAME);
|
||||
QFile configFile(configFileName);
|
||||
QString launcherPath;
|
||||
|
||||
if (configFile.exists()) {
|
||||
if (!configFile.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "Found application config, but could not open it";
|
||||
|
|
|
@ -71,32 +71,44 @@ static QString getTargetDevice(bool hmd, QAudio::Mode mode) {
|
|||
Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled };
|
||||
|
||||
AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) {
|
||||
auto& setting1 = getSetting(true, QAudio::AudioInput);
|
||||
if (setting1.isSet()) {
|
||||
qDebug() << "Device name in settings for HMD, Input" << setting1.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for HMD, Input not set";
|
||||
if (mode == QAudio::AudioInput) {
|
||||
auto& setting1 = getSetting(true, QAudio::AudioInput);
|
||||
if (setting1.isSet()) {
|
||||
qDebug() << "Device name in settings for HMD, Input" << setting1.get();
|
||||
_backupSelectedHMDDeviceName = setting1.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for HMD, Input not set";
|
||||
}
|
||||
}
|
||||
|
||||
auto& setting2 = getSetting(true, QAudio::AudioOutput);
|
||||
if (setting2.isSet()) {
|
||||
qDebug() << "Device name in settings for HMD, Output" << setting2.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for HMD, Output not set";
|
||||
if (mode == QAudio::AudioOutput) {
|
||||
auto& setting2 = getSetting(true, QAudio::AudioOutput);
|
||||
if (setting2.isSet()) {
|
||||
qDebug() << "Device name in settings for HMD, Output" << setting2.get();
|
||||
_backupSelectedHMDDeviceName = setting2.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for HMD, Output not set";
|
||||
}
|
||||
}
|
||||
|
||||
auto& setting3 = getSetting(false, QAudio::AudioInput);
|
||||
if (setting3.isSet()) {
|
||||
qDebug() << "Device name in settings for Desktop, Input" << setting3.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for Desktop, Input not set";
|
||||
if (mode == QAudio::AudioInput) {
|
||||
auto& setting3 = getSetting(false, QAudio::AudioInput);
|
||||
if (setting3.isSet()) {
|
||||
qDebug() << "Device name in settings for Desktop, Input" << setting3.get();
|
||||
_backupSelectedDesktopDeviceName = setting3.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for Desktop, Input not set";
|
||||
}
|
||||
}
|
||||
|
||||
auto& setting4 = getSetting(false, QAudio::AudioOutput);
|
||||
if (setting4.isSet()) {
|
||||
qDebug() << "Device name in settings for Desktop, Output" << setting4.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for Desktop, Output not set";
|
||||
if (mode == QAudio::AudioOutput) {
|
||||
auto& setting4 = getSetting(false, QAudio::AudioOutput);
|
||||
if (setting4.isSet()) {
|
||||
qDebug() << "Device name in settings for Desktop, Output" << setting4.get();
|
||||
_backupSelectedDesktopDeviceName = setting4.get();
|
||||
} else {
|
||||
qDebug() << "Device name in settings for Desktop, Output not set";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,14 @@ void SettingsScriptingInterface::setValue(const QString& setting, const QVariant
|
|||
if (getValue(setting) == value) {
|
||||
return;
|
||||
}
|
||||
if (setting.startsWith("private/")) {
|
||||
if (_restrictPrivateValues) {
|
||||
qWarning() << "SettingsScriptingInterface::setValue -- restricted write: " << setting << value;
|
||||
return;
|
||||
} else {
|
||||
qInfo() << "SettingsScriptingInterface::setValue -- allowing restricted write: " << setting << value;
|
||||
}
|
||||
}
|
||||
// Make a deep-copy of the string.
|
||||
// Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine.
|
||||
QString deepCopy = QString::fromUtf16(setting.utf16());
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
class SettingsScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
SettingsScriptingInterface() { };
|
||||
public:
|
||||
static SettingsScriptingInterface* getInstance();
|
||||
|
||||
|
@ -67,6 +66,16 @@ public slots:
|
|||
|
||||
signals:
|
||||
void valueChanged(const QString& setting, const QVariant& value);
|
||||
|
||||
protected:
|
||||
SettingsScriptingInterface(QObject* parent = nullptr) : QObject(parent) { };
|
||||
bool _restrictPrivateValues { true };
|
||||
};
|
||||
|
||||
class QMLSettingsScriptingInterface : public SettingsScriptingInterface {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QMLSettingsScriptingInterface(QObject* parent) : SettingsScriptingInterface(parent) { _restrictPrivateValues = false; }
|
||||
};
|
||||
|
||||
#endif // hifi_SettingsScriptingInterface_h
|
||||
|
|
10
launchers/darwin/HQ Launcher.entitlements
Normal file
10
launchers/darwin/HQ Launcher.entitlements
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>high-fidelity.hifi</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -50,6 +50,8 @@
|
|||
repeats: YES];
|
||||
NSError *error = nil;
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString *destinationFileName = downloadTask.originalRequest.URL.lastPathComponent;
|
||||
NSString* finalFilePath = [[[Launcher sharedLauncher] getAppPath] stringByAppendingPathComponent:destinationFileName];
|
||||
NSURL *destinationURL = [NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]];
|
||||
|
@ -59,7 +61,12 @@
|
|||
}
|
||||
[fileManager moveItemAtURL:location toURL:destinationURL error:&error];
|
||||
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSURL *oldInterfaceURL = [NSURL URLWithString: [[appPath stringByAppendingString:@"interface.app"] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]];
|
||||
|
||||
if([fileManager fileExistsAtPath:[oldInterfaceURL path]])
|
||||
{
|
||||
[fileManager removeItemAtURL:oldInterfaceURL error:nil];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
NSLog(@"Download Interface: failed to move file to destination -> error: %@", error);
|
||||
|
@ -68,7 +75,6 @@
|
|||
return;
|
||||
}
|
||||
[sharedLauncher setDownloadFilename:destinationFileName];
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString* downloadFileName = [sharedLauncher getDownloadFilename];
|
||||
|
||||
NSLog(@"extract interface zip");
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
@interface DownloadLauncher : NSObject<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLDownloadDelegate> {
|
||||
}
|
||||
|
||||
@property (readonly) bool didBecomeDownloadTask;
|
||||
|
||||
- (void) downloadLauncher:(NSString*) launcherUrl;
|
||||
|
||||
@end
|
||||
|
|
|
@ -8,6 +8,13 @@ static const NSString *kIOError = @"IOError";
|
|||
|
||||
@implementation DownloadLauncher
|
||||
|
||||
-(id)init {
|
||||
if ((self = [super init]) != nil) {
|
||||
_didBecomeDownloadTask = false;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) downloadLauncher:(NSString*)launcherUrl {
|
||||
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:launcherUrl]
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
|
@ -16,8 +23,8 @@ static const NSString *kIOError = @"IOError";
|
|||
|
||||
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
|
||||
NSURLSessionDownloadTask *downloadTask = [defaultSession downloadTaskWithRequest:request];
|
||||
[downloadTask resume];
|
||||
NSURLSessionDataTask *task = [defaultSession dataTaskWithRequest:request];
|
||||
[task resume];
|
||||
}
|
||||
|
||||
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
|
||||
|
@ -45,6 +52,25 @@ static const NSString *kIOError = @"IOError";
|
|||
}
|
||||
}
|
||||
|
||||
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
|
||||
{
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSURLSessionResponseDisposition disposition = NSURLSessionResponseBecomeDownload;
|
||||
if (httpResponse.statusCode != 200) {
|
||||
NSLog(@"expected statusCode 200, got %ld", (long)httpResponse.statusCode);
|
||||
disposition = NSURLSessionResponseCancel;
|
||||
}
|
||||
completionHandler(disposition);
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
{
|
||||
_didBecomeDownloadTask = true;
|
||||
}
|
||||
|
||||
-(void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location {
|
||||
NSLog(@"Did finish downloading to url");
|
||||
@try {
|
||||
|
@ -95,9 +121,14 @@ static const NSString *kIOError = @"IOError";
|
|||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error {
|
||||
NSLog(@"completed; error: %@", error);
|
||||
if (error) {
|
||||
if (_didBecomeDownloadTask && [task class] == [NSURLSessionDataTask class]) {
|
||||
return;
|
||||
}
|
||||
NSLog(@"couldn't complete download: %@", error);
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
} else {
|
||||
NSLog(@"finished downloading Launcher");
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
NSString* defaultBuildTag = [json valueForKey:@"default_tag"];
|
||||
|
||||
NSString* launcherVersion = [launcherValues valueForKey:@"version"];
|
||||
NSString* launcherUrl = [[[launcherValues valueForKey:@"mac"] valueForKey:@"url"] stringByRemovingPercentEncoding];
|
||||
NSString* launcherUrl = [[launcherValues valueForKey:@"mac"] valueForKey:@"url"];
|
||||
|
||||
BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]];
|
||||
|
||||
|
|
|
@ -14,19 +14,32 @@
|
|||
return sharedSettings;
|
||||
}
|
||||
|
||||
- (NSString*) getOldFilePath {
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString* filePath = [appPath stringByAppendingString:@"interface.app/Contents/MacOS/"];
|
||||
return filePath;
|
||||
}
|
||||
|
||||
- (NSString*) getFilePath
|
||||
{
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString* filePath = [appPath stringByAppendingString:@"interface.app/Contents/MacOS/"];
|
||||
|
||||
return filePath;
|
||||
return appPath;
|
||||
}
|
||||
|
||||
- (void) readDataFromJsonFile
|
||||
{
|
||||
NSString* oldPath = [self getOldFilePath];
|
||||
NSString* fileAtOldPath = [oldPath stringByAppendingString:@"config.json"];
|
||||
NSString* filePath = [self getFilePath];
|
||||
NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtOldPath] && ![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||
BOOL success = [[NSFileManager defaultManager] moveItemAtPath:fileAtOldPath toPath:fileAtPath error:nil];
|
||||
NSLog(@"move config to new location -> status: %@", success ? @"SUCCESS" : @"FAILED");
|
||||
}
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||
NSString* jsonString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];
|
||||
NSError * err;
|
||||
|
@ -34,7 +47,6 @@
|
|||
NSDictionary * json;
|
||||
if (data != nil) {
|
||||
json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
|
||||
|
||||
self.loggedIn = [[json valueForKey:@"loggedIn"] boolValue];
|
||||
self.build = [[json valueForKey:@"build_version"] integerValue];
|
||||
self.launcher = [json valueForKey:@"luancherPath"];
|
||||
|
@ -64,18 +76,18 @@
|
|||
NSError * err;
|
||||
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json options:0 error:&err];
|
||||
NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
|
||||
|
||||
NSString* filePath = [self getFilePath];
|
||||
NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
|
||||
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||
NSError * error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:FALSE attributes:nil error:&error];
|
||||
[[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
|
||||
|
||||
|
||||
}
|
||||
[[jsonString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
|
||||
|
||||
|
||||
}
|
||||
|
||||
-(id)init
|
||||
|
|
|
@ -2117,7 +2117,7 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
|
|||
_previousIsTalking = params.isTalking;
|
||||
|
||||
const float TOTAL_EASE_IN_TIME = 0.75f;
|
||||
const float TOTAL_EASE_OUT_TIME = 1.5f;
|
||||
const float TOTAL_EASE_OUT_TIME = 0.75f;
|
||||
if (params.isTalking) {
|
||||
if (_talkIdleInterpTime < 1.0f) {
|
||||
_talkIdleInterpTime += dt / TOTAL_EASE_IN_TIME;
|
||||
|
|
|
@ -49,7 +49,7 @@ void Head::simulate(float deltaTime) {
|
|||
|
||||
// Update audio trailing average for rendering facial animations
|
||||
const float AUDIO_AVERAGING_SECS = 0.05f;
|
||||
const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
|
||||
const float AUDIO_LONG_TERM_AVERAGING_SECS = 15.0f;
|
||||
_averageLoudness = glm::mix(_averageLoudness, audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f));
|
||||
|
||||
if (_longTermAverageLoudness == -1.0f) {
|
||||
|
@ -84,7 +84,7 @@ void Head::simulate(float deltaTime) {
|
|||
if (getHasProceduralBlinkFaceMovement()) {
|
||||
// Detect transition from talking to not; force blink after that and a delay
|
||||
bool forceBlink = false;
|
||||
const float TALKING_LOUDNESS = 100.0f;
|
||||
const float TALKING_LOUDNESS = 150.0f;
|
||||
const float BLINK_AFTER_TALKING = 0.25f;
|
||||
_timeWithoutTalking += deltaTime;
|
||||
if ((_averageLoudness - _longTermAverageLoudness) > TALKING_LOUDNESS) {
|
||||
|
@ -176,7 +176,7 @@ void Head::simulate(float deltaTime) {
|
|||
}
|
||||
|
||||
void Head::calculateMouthShapes(float deltaTime) {
|
||||
const float JAW_OPEN_SCALE = 0.015f;
|
||||
const float JAW_OPEN_SCALE = 0.35f;
|
||||
const float JAW_OPEN_RATE = 0.9f;
|
||||
const float JAW_CLOSE_RATE = 0.90f;
|
||||
const float TIMESTEP_CONSTANT = 0.0032f;
|
||||
|
@ -188,11 +188,13 @@ void Head::calculateMouthShapes(float deltaTime) {
|
|||
const float FUNNEL_SPEED = 2.335f;
|
||||
const float STOP_GAIN = 5.0f;
|
||||
const float NORMAL_HZ = 60.0f; // the update rate the constant values were tuned for
|
||||
const float MAX_DELTA_LOUDNESS = 100.0f;
|
||||
|
||||
float deltaTimeRatio = deltaTime / (1.0f / NORMAL_HZ);
|
||||
|
||||
// From the change in loudness, decide how much to open or close the jaw
|
||||
float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE;
|
||||
float deltaLoudness = glm::max(glm::min(_averageLoudness - _longTermAverageLoudness, MAX_DELTA_LOUDNESS), 0.0f) / MAX_DELTA_LOUDNESS;
|
||||
float audioDelta = powf(deltaLoudness, 2.0f) * JAW_OPEN_SCALE;
|
||||
if (audioDelta > _audioJawOpen) {
|
||||
_audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE * deltaTimeRatio;
|
||||
} else {
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <QJsonArray>
|
||||
|
||||
ModelBaker::ModelBaker(const QUrl& inputModelURL, const QString& bakedOutputDirectory, const QString& originalOutputDirectory, bool hasBeenBaked) :
|
||||
_originalInputModelURL(inputModelURL),
|
||||
_modelURL(inputModelURL),
|
||||
_bakedOutputDir(bakedOutputDirectory),
|
||||
_originalOutputDir(originalOutputDirectory),
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
virtual void setWasAborted(bool wasAborted) override;
|
||||
|
||||
QUrl getModelURL() const { return _modelURL; }
|
||||
QUrl getOriginalInputModelURL() const { return _originalInputModelURL; }
|
||||
virtual QUrl getFullOutputMappingURL() const;
|
||||
QUrl getBakedModelURL() const { return _bakedModelURL; }
|
||||
|
||||
|
@ -67,6 +68,7 @@ protected:
|
|||
void exportScene();
|
||||
|
||||
FBXNode _rootNode;
|
||||
QUrl _originalInputModelURL;
|
||||
QUrl _modelURL;
|
||||
QUrl _outputURLSuffix;
|
||||
QUrl _mappingURL;
|
||||
|
|
|
@ -250,6 +250,7 @@ void TextureBaker::processTexture() {
|
|||
QFile file { _metaTextureFileName };
|
||||
if (!file.open(QIODevice::WriteOnly) || file.write(data) == -1) {
|
||||
handleError("Could not write meta texture for " + _textureURL.toString());
|
||||
return;
|
||||
} else {
|
||||
_outputFiles.push_back(_metaTextureFileName);
|
||||
}
|
||||
|
|
|
@ -585,26 +585,13 @@ void OpenGLDisplayPlugin::updateFrameData() {
|
|||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> OpenGLDisplayPlugin::getHUDOperator() {
|
||||
auto hudPipeline = _hudPipeline;
|
||||
auto hudStereo = isStereo();
|
||||
auto hudCompositeFramebufferSize = _compositeFramebuffer->getSize();
|
||||
std::array<glm::ivec4, 2> hudEyeViewports;
|
||||
for_each_eye([&](Eye eye) {
|
||||
hudEyeViewports[eye] = eyeViewport(eye);
|
||||
});
|
||||
auto hudCompositeFramebufferSize = getRecommendedRenderSize();
|
||||
return [=](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
|
||||
if (hudPipeline && hudTexture) {
|
||||
batch.enableStereo(false);
|
||||
batch.setPipeline(hudPipeline);
|
||||
batch.setResourceTexture(0, hudTexture);
|
||||
if (hudStereo) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(hudEyeViewports[eye]);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), hudCompositeFramebufferSize));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
batch.setViewportTransform(ivec4(uvec2(0), hudCompositeFramebufferSize));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -614,22 +601,14 @@ void OpenGLDisplayPlugin::compositePointer() {
|
|||
const auto& cursorData = _cursorsData[cursorManager.getCursor()->getIcon()];
|
||||
auto cursorTransform = DependencyManager::get<CompositorHelper>()->getReticleTransform(glm::mat4());
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setPipeline(_cursorPipeline);
|
||||
batch.setResourceTexture(0, cursorData.texture);
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(cursorTransform);
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(eyeViewport(eye));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -871,16 +850,6 @@ bool OpenGLDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
|||
return Parent::beginFrameRender(frameIndex);
|
||||
}
|
||||
|
||||
ivec4 OpenGLDisplayPlugin::eyeViewport(Eye eye) const {
|
||||
uvec2 vpSize = _compositeFramebuffer->getSize();
|
||||
vpSize.x /= 2;
|
||||
uvec2 vpPos;
|
||||
if (eye == Eye::Right) {
|
||||
vpPos.x = vpSize.x;
|
||||
}
|
||||
return ivec4(vpPos, vpSize);
|
||||
}
|
||||
|
||||
gpu::gl::GLBackend* OpenGLDisplayPlugin::getGLBackend() {
|
||||
if (!_gpuContext || !_gpuContext->getBackend()) {
|
||||
return nullptr;
|
||||
|
@ -906,7 +875,7 @@ OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
|
|||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateCompositeFramebuffer() {
|
||||
auto renderSize = glm::uvec2(getRecommendedRenderSize());
|
||||
auto renderSize = getRecommendedRenderSize();
|
||||
if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) {
|
||||
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_SRGBA_32, renderSize.x, renderSize.y));
|
||||
}
|
||||
|
|
|
@ -137,7 +137,6 @@ protected:
|
|||
|
||||
void present(const std::shared_ptr<RefreshRateController>& refreshRateController);
|
||||
virtual void swapBuffers();
|
||||
ivec4 eyeViewport(Eye eye) const;
|
||||
|
||||
void render(std::function<void(gpu::Batch& batch)> f);
|
||||
|
||||
|
|
|
@ -68,6 +68,16 @@ glm::mat4 HmdDisplayPlugin::getCullingProjection(const glm::mat4& baseProjection
|
|||
return _cullingProjection;
|
||||
}
|
||||
|
||||
glm::ivec4 HmdDisplayPlugin::eyeViewport(Eye eye) const {
|
||||
uvec2 vpSize = getRecommendedRenderSize();
|
||||
vpSize.x /= 2;
|
||||
uvec2 vpPos;
|
||||
if (eye == Eye::Right) {
|
||||
vpPos.x = vpSize.x;
|
||||
}
|
||||
return ivec4(vpPos, vpSize);
|
||||
}
|
||||
|
||||
#define DISABLE_PREVIEW_MENU_ITEM_DELAY_MS 500
|
||||
|
||||
bool HmdDisplayPlugin::internalActivate() {
|
||||
|
|
|
@ -34,6 +34,8 @@ public:
|
|||
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
||||
bool isDisplayVisible() const override { return isHmdMounted(); }
|
||||
|
||||
ivec4 eyeViewport(Eye eye) const;
|
||||
|
||||
QRect getRecommendedHUDRect() const override final;
|
||||
|
||||
virtual glm::mat4 getHeadPose() const override;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include <PrioritySortUtil.h>
|
||||
#include <Rig.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <EntitySimulation.h>
|
||||
#include <ZoneRenderer.h>
|
||||
#include <PhysicalEntitySimulation.h>
|
||||
|
@ -146,7 +146,7 @@ int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
|
|||
void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
||||
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
||||
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
|
||||
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_entitiesScriptEngine);
|
||||
_entitiesScriptEngine->runInThread();
|
||||
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <QUrl>
|
||||
|
||||
#include <ResourceManager.h>
|
||||
#include <shared/ScriptInitializerMixin.h>
|
||||
|
||||
QList<EntityItemID> EntityEditFilters::getZonesByPosition(glm::vec3& position) {
|
||||
QList<EntityItemID> zones;
|
||||
|
@ -258,7 +259,13 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) {
|
|||
if (hasCorrectSyntax(program)) {
|
||||
// create a QScriptEngine for this script
|
||||
QScriptEngine* engine = new QScriptEngine();
|
||||
engine->evaluate(scriptContents);
|
||||
engine->setObjectName("filter:" + entityID.toString());
|
||||
engine->setProperty("type", "edit_filter");
|
||||
engine->setProperty("fileName", urlString);
|
||||
engine->setProperty("entityID", entityID);
|
||||
engine->globalObject().setProperty("Script", engine->newQObject(engine));
|
||||
DependencyManager::get<ScriptInitializers>()->runScriptInitializers(engine);
|
||||
engine->evaluate(scriptContents, urlString);
|
||||
if (!hadUncaughtExceptions(*engine, urlString)) {
|
||||
// put the engine in the engine map (so we don't leak them, etc...)
|
||||
FilterData filterData;
|
||||
|
|
|
@ -798,7 +798,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
auto lastEdited = lastEditedFromBufferAdjusted;
|
||||
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
||||
// calculate hasGrab once outside the lambda rather than calling it every time inside
|
||||
bool hasGrab = stillHasGrabAction();
|
||||
bool hasGrab = stillHasGrab();
|
||||
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection, hasGrab](quint64 updatedTimestamp, bool valueChanged) {
|
||||
if (hasGrab) {
|
||||
return false;
|
||||
|
@ -1075,16 +1075,13 @@ void EntityItem::setMass(float mass) {
|
|||
|
||||
void EntityItem::setHref(QString value) {
|
||||
auto href = value.toLower();
|
||||
|
||||
// If the string has something and doesn't start with with "hifi://" it shouldn't be set
|
||||
// We allow the string to be empty, because that's the initial state of this property
|
||||
if (!value.isEmpty() &&
|
||||
!(value.toLower().startsWith("hifi://")) &&
|
||||
!(value.toLower().startsWith("file://"))
|
||||
// TODO: serverless-domains will eventually support http and https also
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Let's let the user set the value of this property to anything, then let consumers of the property
|
||||
// decide what to do with it. Currently, the only in-engine consumers are `EntityTreeRenderer::mousePressEvent()`
|
||||
// and `OtherAvatar::handleChangedAvatarEntityData()` (to remove the href property from others' avatar entities).
|
||||
//
|
||||
// We want this property to be as flexible as possible. The value of this property _should_ only be values that can
|
||||
// be handled by `AddressManager::handleLookupString()`. That function will return `false` and not do
|
||||
// anything if the value of this property isn't something that function can handle.
|
||||
withWriteLock([&] {
|
||||
_href = value;
|
||||
});
|
||||
|
@ -1444,7 +1441,7 @@ void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& propert
|
|||
|
||||
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
||||
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
|
||||
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrabAction()) {
|
||||
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrab()) {
|
||||
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||
}
|
||||
if (newPriority != _scriptSimulationPriority) {
|
||||
|
@ -1457,7 +1454,7 @@ void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
|||
void EntityItem::clearScriptSimulationPriority() {
|
||||
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
|
||||
// is only ever called from the code that actually handles the dirty flags, and it knows best.
|
||||
_scriptSimulationPriority = stillHasMyGrabAction() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
||||
_scriptSimulationPriority = stillHasMyGrab() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
||||
}
|
||||
|
||||
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
|
||||
|
@ -2204,7 +2201,7 @@ void EntityItem::enableNoBootstrap() {
|
|||
}
|
||||
|
||||
void EntityItem::disableNoBootstrap() {
|
||||
if (!stillHasMyGrabAction()) {
|
||||
if (!stillHasMyGrab()) {
|
||||
_flags &= ~Simulation::SPECIAL_FLAG_NO_BOOTSTRAPPING;
|
||||
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
|
||||
|
@ -2290,33 +2287,25 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
|
|||
return success;
|
||||
}
|
||||
|
||||
bool EntityItem::stillHasGrabAction() const {
|
||||
return !_grabActions.empty();
|
||||
bool EntityItem::stillHasGrab() const {
|
||||
return !(_grabs.empty());
|
||||
}
|
||||
|
||||
// retutrns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
|
||||
// returns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
|
||||
// (e.g. the action belongs to the MyAvatar instance)
|
||||
bool EntityItem::stillHasMyGrabAction() const {
|
||||
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
|
||||
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
|
||||
while (i != holdActions.end()) {
|
||||
EntityDynamicPointer action = *i;
|
||||
if (action->isMine()) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
bool EntityItem::stillHasMyGrab() const {
|
||||
bool foundGrab = false;
|
||||
if (!_grabs.empty()) {
|
||||
_grabsLock.withReadLock([&] {
|
||||
foreach (const GrabPointer &grab, _grabs) {
|
||||
if (grab->getOwnerID() == Physics::getSessionUUID()) {
|
||||
foundGrab = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
QList<EntityDynamicPointer> farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB);
|
||||
i = farGrabActions.begin();
|
||||
while (i != farGrabActions.end()) {
|
||||
EntityDynamicPointer action = *i;
|
||||
if (action->isMine()) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return false;
|
||||
return foundGrab;
|
||||
}
|
||||
|
||||
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) {
|
||||
|
|
|
@ -569,7 +569,7 @@ public:
|
|||
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
|
||||
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
|
||||
|
||||
bool stillHasMyGrabAction() const;
|
||||
bool stillHasMyGrab() const;
|
||||
|
||||
bool needsRenderUpdate() const { return resultWithReadLock<bool>([&] { return _needsRenderUpdate; }); }
|
||||
void setNeedsRenderUpdate(bool needsRenderUpdate) { withWriteLock([&] { _needsRenderUpdate = needsRenderUpdate; }); }
|
||||
|
@ -585,7 +585,7 @@ protected:
|
|||
void setSimulated(bool simulated) { _simulated = simulated; }
|
||||
|
||||
const QByteArray getDynamicDataInternal() const;
|
||||
bool stillHasGrabAction() const;
|
||||
bool stillHasGrab() const;
|
||||
void setDynamicDataInternal(QByteArray dynamicData);
|
||||
|
||||
virtual void dimensionsChanged() override;
|
||||
|
|
|
@ -2246,8 +2246,8 @@ void EntityTree::preUpdate() {
|
|||
void EntityTree::update(bool simulate) {
|
||||
PROFILE_RANGE(simulation_physics, "UpdateTree");
|
||||
PerformanceTimer perfTimer("updateTree");
|
||||
withWriteLock([&] {
|
||||
if (simulate && _simulation) {
|
||||
if (simulate && _simulation) {
|
||||
withWriteLock([&] {
|
||||
_simulation->updateEntities();
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "Deletes");
|
||||
|
@ -2265,8 +2265,8 @@ void EntityTree::update(bool simulate) {
|
|||
deleteEntities(idsToDelete, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
quint64 EntityTree::getAdjustedConsiderSince(quint64 sinceTime) {
|
||||
|
|
|
@ -107,7 +107,6 @@ void PrepareJointsTask::run(const baker::BakeContextPointer& context, const Inpu
|
|||
glm::quat rotationOffset = itr.value();
|
||||
jointRotationOffsets.insert(jointIndex, rotationOffset);
|
||||
qCDebug(model_baker) << "Joint Rotation Offset added to Rig._jointRotationOffsets : " << " jointName: " << jointName << " jointIndex: " << jointIndex << " rotation offset: " << rotationOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ const char* Assignment::typeToString(Assignment::Type type) {
|
|||
|
||||
QDebug operator<<(QDebug debug, const Assignment &assignment) {
|
||||
debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) <<
|
||||
", Type: " << assignment.getType();
|
||||
", Type: " << assignment.getTypeName() << " (" << assignment.getType() << ")";
|
||||
|
||||
if (!assignment.getPool().isEmpty()) {
|
||||
debug << ", Pool: " << assignment.getPool();
|
||||
|
|
|
@ -29,6 +29,9 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
|
|||
_domainServerTimer(this),
|
||||
_statsTimer(this)
|
||||
{
|
||||
// use <mixer-type> as a temporary targetName name until commonInit can be called later
|
||||
LogHandler::getInstance().setTargetName(QString("<%1>").arg(getTypeName()));
|
||||
|
||||
static const int STATS_TIMEOUT_MS = 1000;
|
||||
_statsTimer.setInterval(STATS_TIMEOUT_MS); // 1s, Qt::CoarseTimer acceptable
|
||||
connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket);
|
||||
|
|
|
@ -274,6 +274,7 @@ enum class EntityVersion : PacketVersion {
|
|||
TextUnlit,
|
||||
ShadowBiasAndDistance,
|
||||
TextEntityFonts,
|
||||
ScriptServerKinematicMotion,
|
||||
|
||||
// Add new versions above here
|
||||
NUM_PACKET_TYPE,
|
||||
|
|
|
@ -740,7 +740,8 @@ bool EntityMotionState::shouldSendBid() const {
|
|||
&& (_region == workload::Region::R1)
|
||||
&& _ownershipState != EntityMotionState::OwnershipState::Unownable
|
||||
&& glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority()
|
||||
&& !_entity->getLocked();
|
||||
&& !_entity->getLocked()
|
||||
&& (!_body->isStaticOrKinematicObject() || _entity->stillHasMyGrab());
|
||||
}
|
||||
|
||||
void EntityMotionState::setRigidBody(btRigidBody* body) {
|
||||
|
|
|
@ -84,6 +84,11 @@ bool isDisabled(QJsonObject metaData) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int PluginManager::instantiate() {
|
||||
auto loaders = getLoadedPlugins();
|
||||
return std::count_if(loaders.begin(), loaders.end(), [](const auto& loader) { return (bool)loader->instance(); });
|
||||
}
|
||||
|
||||
auto PluginManager::getLoadedPlugins() const -> const LoaderList& {
|
||||
static std::once_flag once;
|
||||
static LoaderList loadedPlugins;
|
||||
|
@ -105,6 +110,16 @@ bool isDisabled(QJsonObject metaData) {
|
|||
pluginDir.setNameFilters(QStringList() << "libplugins_lib*.so");
|
||||
#endif
|
||||
auto candidates = pluginDir.entryList();
|
||||
|
||||
if (_enableScriptingPlugins.get()) {
|
||||
QDir scriptingPluginDir{ pluginDir };
|
||||
scriptingPluginDir.cd("scripting");
|
||||
qCDebug(plugins) << "Loading scripting plugins from " << scriptingPluginDir.path();
|
||||
for (auto plugin : scriptingPluginDir.entryList()) {
|
||||
candidates << "scripting/" + plugin;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto plugin : candidates) {
|
||||
qCDebug(plugins) << "Attempting plugin" << qPrintable(plugin);
|
||||
QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
|
||||
|
@ -139,6 +154,8 @@ bool isDisabled(QJsonObject metaData) {
|
|||
qCDebug(plugins) << " " << qPrintable(loader->errorString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "pluginPath does not exit..." << pluginDir;
|
||||
}
|
||||
});
|
||||
return loadedPlugins;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QObject>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "Forward.h"
|
||||
|
||||
|
@ -38,6 +39,7 @@ public:
|
|||
void saveSettings();
|
||||
void setContainer(PluginContainer* container) { _container = container; }
|
||||
|
||||
int instantiate();
|
||||
void shutdown();
|
||||
|
||||
// Application that have statically linked plugins can expose them to the plugin manager with these function
|
||||
|
@ -69,6 +71,9 @@ private:
|
|||
using LoaderList = QList<Loader>;
|
||||
|
||||
const LoaderList& getLoadedPlugins() const;
|
||||
Setting::Handle<bool> _enableScriptingPlugins {
|
||||
"private/enableScriptingPlugins", (bool)qgetenv("enableScriptingPlugins").toInt()
|
||||
};
|
||||
};
|
||||
|
||||
// TODO: we should define this value in CMake, and then use CMake
|
||||
|
|
|
@ -237,6 +237,11 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
|
|||
}
|
||||
}
|
||||
|
||||
QString ScriptEngine::getTypeAsString() const {
|
||||
auto value = QVariant::fromValue(_type).toString();
|
||||
return value.isEmpty() ? "unknown" : value.toLower();
|
||||
}
|
||||
|
||||
QString ScriptEngine::getContext() const {
|
||||
switch (_context) {
|
||||
case CLIENT_SCRIPT:
|
||||
|
|
|
@ -122,6 +122,8 @@ public:
|
|||
class ScriptEngine : public BaseScriptEngine, public EntitiesScriptEngineProvider {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString context READ getContext)
|
||||
Q_PROPERTY(QString type READ getTypeAsString)
|
||||
Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT)
|
||||
public:
|
||||
|
||||
enum Context {
|
||||
|
@ -138,6 +140,7 @@ public:
|
|||
AGENT,
|
||||
AVATAR
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
static int processLevelMaxRetries;
|
||||
ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine"));
|
||||
|
@ -636,6 +639,7 @@ public:
|
|||
|
||||
void setType(Type type) { _type = type; };
|
||||
Type getType() { return _type; };
|
||||
QString getTypeAsString() const;
|
||||
|
||||
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
||||
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
||||
|
|
|
@ -136,24 +136,6 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) {
|
|||
|
||||
QObject* scriptsModel();
|
||||
|
||||
bool NativeScriptInitializers::registerNativeScriptInitializer(NativeScriptInitializer initializer) {
|
||||
return registerScriptInitializer([initializer](ScriptEnginePointer engine) {
|
||||
initializer(qobject_cast<QScriptEngine*>(engine.data()));
|
||||
});
|
||||
}
|
||||
|
||||
bool NativeScriptInitializers::registerScriptInitializer(ScriptInitializer initializer) {
|
||||
if (auto scriptEngines = DependencyManager::get<ScriptEngines>().data()) {
|
||||
scriptEngines->registerScriptInitializer(initializer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
|
||||
_scriptInitializers.push_back(initializer);
|
||||
}
|
||||
|
||||
void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) {
|
||||
if (!_isStopped) {
|
||||
QMutexLocker locker(&_allScriptsMutex);
|
||||
|
@ -590,12 +572,8 @@ void ScriptEngines::quitWhenFinished() {
|
|||
}
|
||||
|
||||
int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) {
|
||||
int ii=0;
|
||||
for (auto initializer : _scriptInitializers) {
|
||||
ii++;
|
||||
initializer(scriptEngine);
|
||||
}
|
||||
return ii;
|
||||
auto nativeCount = DependencyManager::get<ScriptInitializers>()->runScriptInitializers(scriptEngine.data());
|
||||
return nativeCount + ScriptInitializerMixin<ScriptEnginePointer>::runScriptInitializers(scriptEngine);
|
||||
}
|
||||
|
||||
void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
|
||||
|
|
|
@ -48,13 +48,8 @@ class ScriptEngine;
|
|||
* scripts directory of the Interface installation.
|
||||
* <em>Read-only.</em>
|
||||
*/
|
||||
class NativeScriptInitializers : public ScriptInitializerMixin {
|
||||
public:
|
||||
bool registerNativeScriptInitializer(NativeScriptInitializer initializer) override;
|
||||
bool registerScriptInitializer(ScriptInitializer initializer) override;
|
||||
};
|
||||
|
||||
class ScriptEngines : public QObject, public Dependency {
|
||||
class ScriptEngines : public QObject, public Dependency, public ScriptInitializerMixin<ScriptEnginePointer> {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT)
|
||||
|
@ -62,11 +57,9 @@ class ScriptEngines : public QObject, public Dependency {
|
|||
Q_PROPERTY(QString debugScriptUrl READ getDebugScriptUrl WRITE setDebugScriptUrl)
|
||||
|
||||
public:
|
||||
using ScriptInitializer = ScriptInitializerMixin::ScriptInitializer;
|
||||
|
||||
ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride = QUrl());
|
||||
void registerScriptInitializer(ScriptInitializer initializer);
|
||||
int runScriptInitializers(ScriptEnginePointer engine);
|
||||
int runScriptInitializers(ScriptEnginePointer engine) override;
|
||||
|
||||
void loadScripts();
|
||||
void saveScripts();
|
||||
|
||||
|
@ -347,7 +340,6 @@ protected:
|
|||
QHash<QUrl, ScriptEnginePointer> _scriptEnginesHash;
|
||||
QSet<ScriptEnginePointer> _allKnownScriptEngines;
|
||||
QMutex _allScriptsMutex;
|
||||
std::list<ScriptInitializer> _scriptInitializers;
|
||||
ScriptsModel _scriptsModel;
|
||||
ScriptsModelFilter _scriptsModelFilter;
|
||||
std::atomic<bool> _isStopped { false };
|
||||
|
|
|
@ -9,30 +9,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <QSharedPointer>
|
||||
#include "../DependencyManager.h"
|
||||
|
||||
class QScriptEngine;
|
||||
class ScriptEngine;
|
||||
|
||||
class ScriptInitializerMixin : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
template <typename T> class ScriptInitializerMixin {
|
||||
public:
|
||||
using ScriptInitializer = std::function<void(T)>;
|
||||
virtual void registerScriptInitializer(ScriptInitializer initializer) {
|
||||
InitializerLock lock(_scriptInitializerMutex);
|
||||
_scriptInitializers.push_back(initializer);
|
||||
}
|
||||
virtual int runScriptInitializers(T engine) {
|
||||
InitializerLock lock(_scriptInitializerMutex);
|
||||
return std::count_if(_scriptInitializers.begin(), _scriptInitializers.end(),
|
||||
[engine](auto initializer){ initializer(engine); return true; }
|
||||
);
|
||||
}
|
||||
virtual ~ScriptInitializerMixin() {}
|
||||
protected:
|
||||
std::mutex _scriptInitializerMutex;
|
||||
using InitializerLock = std::lock_guard<std::mutex>;
|
||||
std::list<ScriptInitializer> _scriptInitializers;
|
||||
};
|
||||
|
||||
class ScriptInitializers : public ScriptInitializerMixin<QScriptEngine*>, public Dependency {
|
||||
public:
|
||||
// Lightweight `QScriptEngine*` initializer (only depends on built-in Qt components)
|
||||
// example registration:
|
||||
// eg: [&](QScriptEngine* engine) -> bool {
|
||||
// eg: [&](QScriptEngine* engine) {
|
||||
// engine->globalObject().setProperties("API", engine->newQObject(...instance...))
|
||||
// return true;
|
||||
// }
|
||||
using NativeScriptInitializer = std::function<void(QScriptEngine*)>;
|
||||
virtual bool registerNativeScriptInitializer(NativeScriptInitializer initializer) = 0;
|
||||
|
||||
// Heavyweight `ScriptEngine*` initializer (tightly coupled to Interface and script-engine library internals)
|
||||
// eg: [&](ScriptEnginePointer scriptEngine) -> bool {
|
||||
// engine->registerGlobalObject("API", ...instance..);
|
||||
// return true;
|
||||
// }
|
||||
using ScriptEnginePointer = QSharedPointer<ScriptEngine>;
|
||||
using ScriptInitializer = std::function<void(ScriptEnginePointer)>;
|
||||
virtual bool registerScriptInitializer(ScriptInitializer initializer) { return false; };
|
||||
// };
|
||||
};
|
||||
|
|
|
@ -43,3 +43,7 @@ set(DIR "pcmCodec")
|
|||
add_subdirectory(${DIR})
|
||||
set(DIR "hifiCodec")
|
||||
add_subdirectory(${DIR})
|
||||
|
||||
# example plugins
|
||||
set(DIR "KasenAPIExample")
|
||||
add_subdirectory(${DIR})
|
||||
|
|
3
plugins/KasenAPIExample/CMakeLists.txt
Normal file
3
plugins/KasenAPIExample/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME KasenAPIExample)
|
||||
setup_hifi_client_server_plugin(scripting)
|
||||
link_hifi_libraries(shared plugins avatars networking graphics gpu)
|
56
plugins/KasenAPIExample/src/ExampleScriptPlugin.h
Normal file
56
plugins/KasenAPIExample/src/ExampleScriptPlugin.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// ExampleScriptPlugin.h
|
||||
// plugins/KasenAPIExample/src
|
||||
//
|
||||
// Created by Kasen IO on 2019.07.14 | realities.dev | kasenvr@gmail.com
|
||||
// Copyright 2019 Kasen IO
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Supporting file containing all QtScript specific integration.
|
||||
|
||||
#ifndef EXAMPLE_SCRIPT_PLUGIN_H
|
||||
#define EXAMPLE_SCRIPT_PLUGIN_H
|
||||
|
||||
#if DEV_BUILD
|
||||
#pragma message("QtScript is deprecated see: doc.qt.io/qt-5/topics-scripting.html")
|
||||
#endif
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QCoreApplication>
|
||||
#include <shared/ScriptInitializerMixin.h>
|
||||
|
||||
namespace example {
|
||||
|
||||
extern const QLoggingCategory& logger;
|
||||
|
||||
inline void setGlobalInstance(QScriptEngine* engine, const QString& name, QObject* object) {
|
||||
auto value = engine->newQObject(object, QScriptEngine::QtOwnership);
|
||||
engine->globalObject().setProperty(name, value);
|
||||
qCDebug(logger) << "setGlobalInstance" << name << engine->property("fileName");
|
||||
}
|
||||
|
||||
class ScriptPlugin : public QObject {
|
||||
Q_OBJECT
|
||||
QString _version;
|
||||
Q_PROPERTY(QString version MEMBER _version CONSTANT)
|
||||
protected:
|
||||
inline ScriptPlugin(const QString& name, const QString& version) : _version(version) {
|
||||
setObjectName(name);
|
||||
if (!DependencyManager::get<ScriptInitializers>()) {
|
||||
qCWarning(logger) << "COULD NOT INITIALIZE (ScriptInitializers unavailable)" << qApp << this;
|
||||
return;
|
||||
}
|
||||
qCWarning(logger) << "registering w/ScriptInitializerMixin..." << DependencyManager::get<ScriptInitializers>().data();
|
||||
DependencyManager::get<ScriptInitializers>()->registerScriptInitializer(
|
||||
[this](QScriptEngine* engine) { setGlobalInstance(engine, objectName(), this); });
|
||||
}
|
||||
public slots:
|
||||
inline QString toString() const { return QString("[%1 version=%2]").arg(objectName()).arg(_version); }
|
||||
};
|
||||
|
||||
} // namespace example
|
||||
|
||||
#endif
|
139
plugins/KasenAPIExample/src/KasenAPIExample.cpp
Normal file
139
plugins/KasenAPIExample/src/KasenAPIExample.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// KasenAPIExample.cpp
|
||||
// plugins/KasenAPIExample/src
|
||||
//
|
||||
// Created by Kasen IO on 2019.07.14 | realities.dev | kasenvr@gmail.com
|
||||
// Copyright 2019 Kasen IO
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Example of prototyping new JS APIs by leveraging the existing plugin system.
|
||||
|
||||
#include "ExampleScriptPlugin.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <AvatarHashMap.h>
|
||||
|
||||
namespace custom_api_example {
|
||||
|
||||
QLoggingCategory logger{ "custom_api_example" };
|
||||
|
||||
class KasenAPIExample : public example::ScriptPlugin {
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "KasenAPIExample" FILE "plugin.json")
|
||||
public:
|
||||
KasenAPIExample() : example::ScriptPlugin("KasenAPIExample", "0.0.1") {
|
||||
qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread();
|
||||
}
|
||||
|
||||
public slots:
|
||||
/**jsdoc
|
||||
* Returns current microseconds (usecs) since Epoch. note: 1000usecs == 1ms
|
||||
* @example <caption>Measure current setTimeout accuracy.</caption>
|
||||
* var expected = 1000;
|
||||
* var start = KasenAPIExample.now();
|
||||
* Script.setTimeout(function () {
|
||||
* var elapsed = (KasenAPIExample.now() - start)/1000;
|
||||
* print("expected (ms):", expected, "actual (ms):", elapsed);
|
||||
* }, expected);
|
||||
*/
|
||||
QVariant now() const {
|
||||
return usecTimestampNow();
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Returns the available blendshape names for an avatar.
|
||||
* @example <caption>Get blendshape names</caption>
|
||||
* print(JSON.stringify(KasenAPIExample.getBlendshapeNames(MyAvatar.sessionUUID)));
|
||||
*/
|
||||
QStringList getBlendshapeNames(const QUuid& avatarID) const {
|
||||
QVector<QString> out;
|
||||
if (auto head = getAvatarHead(avatarID)) {
|
||||
for (const auto& kv : head->getBlendshapeMap().toStdMap()) {
|
||||
if (kv.second >= out.size()) out.resize(kv.second+1);
|
||||
out[kv.second] = kv.first;
|
||||
}
|
||||
}
|
||||
return out.toList();
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Returns a key-value object with active (non-zero) blendshapes.
|
||||
* eg: { JawOpen: 1.0, ... }
|
||||
* @example <caption>Get active blendshape map</caption>
|
||||
* print(JSON.stringify(KasenAPIExample.getActiveBlendshapes(MyAvatar.sessionUUID)));
|
||||
*/
|
||||
QVariant getActiveBlendshapes(const QUuid& avatarID) const {
|
||||
if (auto head = getAvatarHead(avatarID)) {
|
||||
return head->toJson()["blendShapes"].toVariant();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QVariant getBlendshapeMapping(const QUuid& avatarID) const {
|
||||
QVariantMap out;
|
||||
if (auto head = getAvatarHead(avatarID)) {
|
||||
for (const auto& kv : head->getBlendshapeMap().toStdMap()) {
|
||||
out[kv.first] = kv.second;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QVariant getBlendshapes(const QUuid& avatarID) const {
|
||||
QVariantMap result;
|
||||
if (auto head = getAvatarHead(avatarID)) {
|
||||
QStringList names = getBlendshapeNames(avatarID);
|
||||
auto states = head->getBlendshapeStates();
|
||||
result = {
|
||||
{ "base", zipNonZeroValues(names, states.base) },
|
||||
{ "summed", zipNonZeroValues(names, states.summed) },
|
||||
{ "transient", zipNonZeroValues(names, states.transient) },
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static QVariantMap zipNonZeroValues(const QStringList& keys, const QVector<float>& values) {
|
||||
QVariantMap out;
|
||||
for (int i=1; i < values.size(); i++) {
|
||||
if (fabs(values[i]) > 1.0e-6) {
|
||||
out[keys.value(i)] = values[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
struct _HeadHelper : public HeadData {
|
||||
QMap<QString,int> getBlendshapeMap() const {
|
||||
return _blendshapeLookupMap;
|
||||
}
|
||||
struct States { QVector<float> base, summed, transient; };
|
||||
States getBlendshapeStates() const {
|
||||
return {
|
||||
_blendshapeCoefficients,
|
||||
_summedBlendshapeCoefficients,
|
||||
_transientBlendshapeCoefficients
|
||||
};
|
||||
}
|
||||
};
|
||||
static const _HeadHelper* getAvatarHead(const QUuid& avatarID) {
|
||||
auto avatars = DependencyManager::get<AvatarHashMap>();
|
||||
auto avatar = avatars ? avatars->getAvatarBySessionID(avatarID) : nullptr;
|
||||
auto head = avatar ? avatar->getHeadData() : nullptr;
|
||||
return reinterpret_cast<const _HeadHelper*>(head);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const QLoggingCategory& example::logger{ custom_api_example::logger };
|
||||
|
||||
#include "KasenAPIExample.moc"
|
21
plugins/KasenAPIExample/src/plugin.json
Normal file
21
plugins/KasenAPIExample/src/plugin.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name":"Kasen JS API Example",
|
||||
"version": 1,
|
||||
"package": {
|
||||
"author": "Revofire",
|
||||
"homepage": "www.realities.dev",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"hifi-interface": ">= 0.83.0",
|
||||
"hifi-assignment-client": ">= 0.83.0"
|
||||
},
|
||||
"config": {
|
||||
"client": true,
|
||||
"entity_client": true,
|
||||
"entity_server": true,
|
||||
"edit_filter": true,
|
||||
"agent": true,
|
||||
"avatar": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,11 +16,13 @@
|
|||
// *************************************
|
||||
// #region dependencies
|
||||
|
||||
|
||||
// The information needed to properly use the sprite sheets and get the general information
|
||||
// about the emojis
|
||||
var emojiList = Script.require("./emojiApp/resources/modules/emojiList.js");
|
||||
var customEmojiList = Script.require("./emojiApp/resources/modules/customEmojiList.js");
|
||||
|
||||
|
||||
// #endregion
|
||||
// *************************************
|
||||
// END dependencies
|
||||
|
@ -181,6 +183,7 @@ function maybeClearClapSoundInterval() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// URLs for this fn are relative to SimplifiedEmoteIndicator.qml
|
||||
function toggleReaction(reaction) {
|
||||
var reactionEnding = reactionsBegun.indexOf(reaction) > -1;
|
||||
|
@ -192,6 +195,7 @@ function toggleReaction(reaction) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function maybeDeleteRemoteIndicatorTimeout() {
|
||||
if (restoreEmoteIndicatorTimeout) {
|
||||
Script.clearTimeout(restoreEmoteIndicatorTimeout);
|
||||
|
@ -199,6 +203,7 @@ function maybeDeleteRemoteIndicatorTimeout() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
var reactionsBegun = [];
|
||||
var pointReticle = null;
|
||||
var mouseMoveEventsConnected = false;
|
||||
|
@ -229,6 +234,7 @@ function beginReactionWrapper(reaction) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Checks to see if there are any reticle entities already to delete
|
||||
function deleteOldReticles() {
|
||||
MyAvatar.getAvatarEntitiesVariant()
|
||||
|
@ -313,6 +319,7 @@ function triggerReactionWrapper(reaction) {
|
|||
}, WAIT_TO_RESTORE_EMOTE_INDICATOR_ICON_MS);
|
||||
}
|
||||
|
||||
|
||||
function maybeClearReticleUpdateLimiterTimeout() {
|
||||
if (reticleUpdateRateLimiterTimer) {
|
||||
Script.clearTimeout(reticleUpdateRateLimiterTimer);
|
||||
|
@ -393,6 +400,7 @@ function onMessageFromEmoteAppBar(message) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function getEmojiURLFromCode(code) {
|
||||
var emojiObject = emojiList[emojiCodeMap[code]];
|
||||
var emojiFilename;
|
||||
|
@ -405,6 +413,7 @@ function getEmojiURLFromCode(code) {
|
|||
return "../../emojiApp/resources/images/emojis/52px/" + emojiFilename;
|
||||
}
|
||||
|
||||
|
||||
function updateEmoteIndicatorIcon(iconURL) {
|
||||
emoteAppBarWindow.sendToQml({
|
||||
"source": "simplifiedEmote.js",
|
||||
|
@ -451,7 +460,10 @@ function keyPressHandler(event) {
|
|||
} else if (event.text === RAISE_HAND_KEY) {
|
||||
toggleReaction("raiseHand");
|
||||
} else if (event.text === APPLAUD_KEY) {
|
||||
toggleReaction("applaud");
|
||||
// Make sure this doesn't get triggered if you are flying, falling, or jumping
|
||||
if (!MyAvatar.isInAir()) {
|
||||
toggleReaction("applaud");
|
||||
}
|
||||
} else if (event.text === POINT_KEY) {
|
||||
toggleReaction("point");
|
||||
} else if (event.text === EMOTE_WINDOW && !(Settings.getValue("io.highfidelity.isEditing", false))) {
|
||||
|
@ -639,6 +651,7 @@ function unload() {
|
|||
// *************************************
|
||||
// #region EMOJI_UTILITY
|
||||
|
||||
|
||||
var EMOJI_52_BASE_URL = "../../resources/images/emojis/52px/";
|
||||
function selectedEmoji(code) {
|
||||
emojiAPI.addEmoji(code);
|
||||
|
@ -744,6 +757,7 @@ function toggleEmojiApp() {
|
|||
emojiAPI.registerAvimojiQMLWindow(emojiAppWindow);
|
||||
}
|
||||
|
||||
|
||||
// #endregion
|
||||
// *************************************
|
||||
// END EMOJI_MAIN
|
||||
|
|
|
@ -445,7 +445,7 @@ void DomainBaker::handleFinishedModelBaker() {
|
|||
|
||||
// enumerate the QJsonRef values for the URL of this model from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getModelURL())) {
|
||||
for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getOriginalInputModelURL())) {
|
||||
QString property = propertyEntityPair.first;
|
||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||
auto entity = propertyEntityPair.second.toObject();
|
||||
|
@ -485,10 +485,10 @@ void DomainBaker::handleFinishedModelBaker() {
|
|||
}
|
||||
|
||||
// remove the baked URL from the multi hash of entities needing a re-write
|
||||
_entitiesNeedingRewrite.remove(baker->getModelURL());
|
||||
_entitiesNeedingRewrite.remove(baker->getOriginalInputModelURL());
|
||||
|
||||
// drop our shared pointer to this baker so that it gets cleaned up
|
||||
_modelBakers.remove(baker->getModelURL());
|
||||
_modelBakers.remove(baker->getOriginalInputModelURL());
|
||||
|
||||
// emit progress to tell listeners how many models we have baked
|
||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||
|
|
Loading…
Reference in a new issue