Merge branch 'master' of https://github.com/highfidelity/hifi into 21215

This commit is contained in:
trent 2017-03-22 14:20:37 -04:00
commit 83d69e65b3
21 changed files with 1381 additions and 136 deletions

View file

@ -58,6 +58,8 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
DependencyManager::set<AudioScriptingInterface>();
DependencyManager::set<ResourceCacheSharedItems>();
DependencyManager::set<SoundCache>();
DependencyManager::set<AudioInjectorManager>();
@ -324,7 +326,26 @@ void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) {
void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) {
switch (killedNode->getType()) {
case NodeType::EntityServer: {
clear();
// Before we clear, make sure this was our only entity server.
// Otherwise we're assuming that we have "trading" entity servers
// (an old one going away and a new one coming onboard)
// and that we shouldn't clear here because we're still doing work.
bool hasAnotherEntityServer = false;
auto nodeList = DependencyManager::get<NodeList>();
nodeList->eachNodeBreakable([&hasAnotherEntityServer, &killedNode](const SharedNodePointer& node){
if (node->getType() == NodeType::EntityServer && node->getUUID() != killedNode->getUUID()) {
// we're talking to > 1 entity servers, we know we won't clear
hasAnotherEntityServer = true;
return false;
}
return true;
});
if (!hasAnotherEntityServer) {
clear();
}
break;
}
@ -395,7 +416,8 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) {
void EntityScriptServer::resetEntitiesScriptEngine() {
auto engineName = QString("about:Entities %1").arg(++_entitiesScriptEngineCount);
auto newEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName));
auto newEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName),
&ScriptEngine::deleteLater);
auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor);
newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);

View file

@ -740,23 +740,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
});
auto& audioScriptingInterface = AudioScriptingInterface::getInstance();
auto audioScriptingInterface = DependencyManager::set<AudioScriptingInterface>();
connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);
connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit);
connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);
connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled);
connect(audioIO.data(), &AudioClient::mutedByMixer, &audioScriptingInterface, &AudioScriptingInterface::mutedByMixer);
connect(audioIO.data(), &AudioClient::receivedFirstPacket, &audioScriptingInterface, &AudioScriptingInterface::receivedFirstPacket);
connect(audioIO.data(), &AudioClient::disconnected, &audioScriptingInterface, &AudioScriptingInterface::disconnected);
connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer);
connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket);
connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected);
connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) {
auto audioClient = DependencyManager::get<AudioClient>();
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition();
float distance = glm::distance(myAvatarPosition, position);
bool shouldMute = !audioClient->isMuted() && (distance < radius);
if (shouldMute) {
audioClient->toggleMute();
AudioScriptingInterface::getInstance().environmentMuted();
audioScriptingInterface->environmentMuted();
}
});
@ -1181,10 +1182,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// set the local loopback interface for local sounds
AudioInjector::setLocalAudioInterface(audioIO.data());
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
connect(audioIO.data(), &AudioClient::noiseGateOpened, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateOpened);
connect(audioIO.data(), &AudioClient::noiseGateClosed, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateClosed);
connect(audioIO.data(), &AudioClient::inputReceived, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::inputReceived);
audioScriptingInterface->setLocalAudioInterface(audioIO.data());
connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened);
connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed);
connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), &AudioScriptingInterface::inputReceived);
this->installEventFilter(this);
@ -1949,7 +1950,7 @@ void Application::initializeUi() {
// For some reason there is already an "Application" object in the QML context,
// though I can't find it. Hence, "ApplicationInterface"
rootContext->setContextProperty("ApplicationInterface", this);
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
rootContext->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
rootContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());

View file

@ -431,7 +431,9 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance,
thisFace, thisSurfaceNormal, thisExtraInfo)) {
bool isDrawInFront = thisOverlay->getDrawInFront();
if (thisDistance < bestDistance && (!bestIsFront || isDrawInFront)) {
if ((bestIsFront && isDrawInFront && thisDistance < bestDistance)
|| (!bestIsFront && (isDrawInFront || thisDistance < bestDistance))) {
bestIsFront = isDrawInFront;
bestDistance = thisDistance;
result.intersects = true;

View file

@ -19,11 +19,6 @@ void registerAudioMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue);
}
AudioScriptingInterface& AudioScriptingInterface::getInstance() {
static AudioScriptingInterface staticInstance;
return staticInstance;
}
AudioScriptingInterface::AudioScriptingInterface() :
_localAudioInterface(NULL)
{

View file

@ -14,18 +14,20 @@
#include <AbstractAudioInterface.h>
#include <AudioInjector.h>
#include <DependencyManager.h>
#include <Sound.h>
class ScriptAudioInjector;
class AudioScriptingInterface : public QObject {
class AudioScriptingInterface : public QObject, public Dependency {
Q_OBJECT
public:
static AudioScriptingInterface& getInstance();
SINGLETON_DEPENDENCY
public:
void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; }
protected:
// this method is protected to stop C++ callers from calling, but invokable from script
Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
@ -42,6 +44,7 @@ signals:
private:
AudioScriptingInterface();
AbstractAudioInterface* _localAudioInterface;
};

View file

@ -464,17 +464,17 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
void ScriptEngine::scriptErrorMessage(const QString& message) {
qCCritical(scriptengine) << qPrintable(message);
emit errorMessage(message);
emit errorMessage(message, getFilename());
}
void ScriptEngine::scriptWarningMessage(const QString& message) {
qCWarning(scriptengine) << message;
emit warningMessage(message);
emit warningMessage(message, getFilename());
}
void ScriptEngine::scriptInfoMessage(const QString& message) {
qCInfo(scriptengine) << message;
emit infoMessage(message);
emit infoMessage(message, getFilename());
}
// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
@ -627,6 +627,9 @@ void ScriptEngine::init() {
qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue);
qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue);
// NOTE: You do not want to end up creating new instances of singletons here. They will be on the ScriptEngine thread
// and are likely to be unusable if we "reset" the ScriptEngine by creating a new one (on a whole new thread).
registerGlobalObject("Script", this);
{
@ -638,7 +641,8 @@ void ScriptEngine::init() {
resetModuleCache();
}
registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
registerGlobalObject("Audio", DependencyManager::get<AudioScriptingInterface>().data());
registerGlobalObject("Entities", entityScriptingInterface.data());
registerGlobalObject("Quat", &_quatLibrary);
registerGlobalObject("Vec3", &_vec3Library);
@ -1347,7 +1351,7 @@ QUrl ScriptEngine::resourcesPath() const {
}
void ScriptEngine::print(const QString& message) {
emit printedMessage(message);
emit printedMessage(message, getFilename());
}
// Script.require.resolve -- like resolvePath, but performs more validation and throws exceptions on invalid module identifiers (for consistency with Node.js)

View file

@ -236,10 +236,10 @@ signals:
void scriptEnding();
void finished(const QString& fileNameString, ScriptEngine* engine);
void cleanupMenuItem(const QString& menuItemString);
void printedMessage(const QString& message);
void errorMessage(const QString& message);
void warningMessage(const QString& message);
void infoMessage(const QString& message);
void printedMessage(const QString& message, const QString& scriptName);
void errorMessage(const QString& message, const QString& scriptName);
void warningMessage(const QString& message, const QString& scriptName);
void infoMessage(const QString& message, const QString& scriptName);
void runningStateChanged();
void loadScript(const QString& scriptName, bool isUserLoaded);
void reloadScript(const QString& scriptName, bool isUserLoaded);

View file

@ -34,34 +34,24 @@ ScriptsModel& getScriptsModel() {
return scriptsModel;
}
void ScriptEngines::onPrintedMessage(const QString& message) {
auto scriptEngine = qobject_cast<ScriptEngine*>(sender());
auto scriptName = scriptEngine ? scriptEngine->getFilename() : "";
void ScriptEngines::onPrintedMessage(const QString& message, const QString& scriptName) {
emit printedMessage(message, scriptName);
}
void ScriptEngines::onErrorMessage(const QString& message) {
auto scriptEngine = qobject_cast<ScriptEngine*>(sender());
auto scriptName = scriptEngine ? scriptEngine->getFilename() : "";
void ScriptEngines::onErrorMessage(const QString& message, const QString& scriptName) {
emit errorMessage(message, scriptName);
}
void ScriptEngines::onWarningMessage(const QString& message) {
auto scriptEngine = qobject_cast<ScriptEngine*>(sender());
auto scriptName = scriptEngine ? scriptEngine->getFilename() : "";
void ScriptEngines::onWarningMessage(const QString& message, const QString& scriptName) {
emit warningMessage(message, scriptName);
}
void ScriptEngines::onInfoMessage(const QString& message) {
auto scriptEngine = qobject_cast<ScriptEngine*>(sender());
auto scriptName = scriptEngine ? scriptEngine->getFilename() : "";
void ScriptEngines::onInfoMessage(const QString& message, const QString& scriptName) {
emit infoMessage(message, scriptName);
}
void ScriptEngines::onErrorLoadingScript(const QString& url) {
auto scriptEngine = qobject_cast<ScriptEngine*>(sender());
auto scriptName = scriptEngine ? scriptEngine->getFilename() : "";
emit errorLoadingScript(url, scriptName);
emit errorLoadingScript(url);
}
ScriptEngines::ScriptEngines(ScriptEngine::Context context)

View file

@ -79,13 +79,13 @@ signals:
void errorMessage(const QString& message, const QString& engineName);
void warningMessage(const QString& message, const QString& engineName);
void infoMessage(const QString& message, const QString& engineName);
void errorLoadingScript(const QString& url, const QString& engineName);
void errorLoadingScript(const QString& url);
public slots:
void onPrintedMessage(const QString& message);
void onErrorMessage(const QString& message);
void onWarningMessage(const QString& message);
void onInfoMessage(const QString& message);
void onPrintedMessage(const QString& message, const QString& scriptName);
void onErrorMessage(const QString& message, const QString& scriptName);
void onWarningMessage(const QString& message, const QString& scriptName);
void onInfoMessage(const QString& message, const QString& scriptName);
void onErrorLoadingScript(const QString& url);
protected slots:

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M331.8,283.4c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C342.1,306.6,331.8,296.2,331.8,283.4z"/>
<path d="M277.8,350.9c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C288.1,374.2,277.8,363.8,277.8,350.9z"/>
<path d="M216.3,368.8c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C226.7,392,216.3,381.6,216.3,368.8z"/>
<path d="M169.9,308.9c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C180.3,332.1,169.9,321.7,169.9,308.9z"/>
<path d="M251.2,447.4c-4.9-3.6-8.3-9.1-9.2-15.3c-0.9-6,0.6-12.3,4.2-17.2c3.6-4.9,9.1-8.3,15.2-9.1c6-0.9,12.3,0.6,17.3,4.3
c4.9,3.6,8.3,9.1,9.1,15.2c0.9,6-0.6,12.3-4.2,17.2s-9.1,8.3-15.2,9.1C262.4,452.6,256.1,451,251.2,447.4z"/>
<path d="M67.6,246.1c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C78,269.3,67.6,258.8,67.6,246.1z"/>
<path d="M178.8,199.5c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C189.1,222.7,178.8,212.2,178.8,199.5z"/>
<path d="M250.3,293.9c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C260.7,317.1,250.3,306.6,250.3,293.9z"/>
<path d="M413,242.1c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C423.5,265.3,413,255,413,242.1z"/>
<path d="M302.1,203.7c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C312.6,226.9,302.1,216.5,302.1,203.7z"/>
<path d="M132.3,113.5c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C142.8,136.6,132.3,126.2,132.3,113.5z"/>
<path d="M366.6,136.7c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C377.1,159.9,366.6,149.5,366.6,136.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 960 560" style="enable-background:new 0 0 960 560;" xml:space="preserve">
<g>
<g>
<path style="fill:#333333;" d="M478.879,127.676c-83.872,0-152.325,68.454-152.325,152.325s68.454,152.325,152.325,152.325
s152.325-67.837,152.325-152.325C631.204,196.13,563.366,127.676,478.879,127.676z"/>
<path style="fill:#FFFFFF;" d="M478.881,437.281C392.156,437.281,321.6,366.725,321.6,280s70.557-157.281,157.281-157.281
S636.157,193.275,636.157,280S565.606,437.281,478.881,437.281z M478.881,132.627c-81.263,0-147.373,66.115-147.373,147.373
s66.11,147.373,147.373,147.373c81.258,0,147.368-66.115,147.368-147.373S560.138,132.627,478.881,132.627z"/>
</g>
<g>
<rect x="459.145" y="4.952" style="fill:#333333;" width="40.086" height="75.237"/>
<path style="fill:#FFFFFF;" d="M504.183,85.147h-49.99V0h49.99V85.147z M464.1,75.239h30.174V9.908H464.1V75.239z"/>
</g>
<g>
<rect x="272.766" y="90.696" transform="matrix(-0.707 -0.7072 0.7072 -0.707 451.5123 408.5368)" style="fill:#333333;" width="75.236" height="40.085"/>
<path style="fill:#FFFFFF;" d="M322.809,158.519l-60.198-60.212l35.351-35.346l60.198,60.212L322.809,158.519z M276.621,98.307
l46.188,46.202l21.34-21.335l-46.188-46.202L276.621,98.307z"/>
</g>
<g>
<rect x="201.98" y="257.8" style="fill:#333333;" width="75.237" height="40.086"/>
<path style="fill:#FFFFFF;" d="M282.17,302.845h-85.142V252.85h85.142V302.845z M206.936,292.937h65.327v-30.179h-65.327V292.937z
"/>
</g>
<g>
<rect x="287.46" y="408.97" transform="matrix(0.7072 0.707 -0.707 0.7072 405.7749 -86.6482)" style="fill:#333333;" width="40.085" height="75.236"/>
<path style="fill:#FFFFFF;" d="M295.083,494.359l-35.355-35.346l60.198-60.212l35.355,35.346L295.083,494.359z M273.738,459.013
l21.345,21.335l46.187-46.202l-21.345-21.335L273.738,459.013z"/>
</g>
<g>
<rect x="454.827" y="479.812" style="fill:#333333;" width="40.086" height="75.237"/>
<path style="fill:#FFFFFF;" d="M499.868,560h-49.995v-85.137h49.995V560z M459.781,550.091h30.179V484.77h-30.179V550.091z"/>
</g>
<g>
<rect x="606.017" y="429.505" transform="matrix(0.707 0.7072 -0.7072 0.707 506.5034 -323.4691)" style="fill:#333333;" width="75.236" height="40.085"/>
<path style="fill:#FFFFFF;" d="M656.06,497.32l-60.198-60.212l35.351-35.346l60.198,60.212L656.06,497.32z M609.872,437.107
l46.187,46.202l21.34-21.335l-46.188-46.202L609.872,437.107z"/>
</g>
<g>
<rect x="676.839" y="262.117" style="fill:#333333;" width="75.237" height="40.086"/>
<path style="fill:#FFFFFF;" d="M757.032,307.16h-85.147v-49.995h85.147V307.16z M681.792,297.252h65.332v-30.179h-65.332V297.252z
"/>
</g>
<g>
<rect x="626.205" y="75.756" transform="matrix(-0.7072 -0.707 0.707 -0.7072 1023.1211 650.4535)" style="fill:#333333;" width="40.085" height="75.236"/>
<path style="fill:#FFFFFF;" d="M633.825,161.161l-35.351-35.346l60.198-60.212l35.351,35.346L633.825,161.161z M612.485,125.815
l21.34,21.335l46.188-46.202l-21.34-21.335L612.485,125.815z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="3.44 0 735.338 557.9" style="enable-background:new 3.44 0 735.338 557.9;" xml:space="preserve">
<g>
<g>
<rect x="503.95" y="260.767" style="fill:#333333;" width="227.728" height="36.376"/>
<path style="fill:#FFFFFF;" d="M738.778,304.24H496.854v-50.566h241.924V304.24z M511.052,290.042H724.58v-22.17H511.052V290.042z
"/>
</g>
<g>
<g>
<g>
<rect x="426.085" y="465.518" transform="matrix(-0.9213 -0.3888 0.3888 -0.9213 849.3369 1139.2869)" style="fill:#333333;" width="227.719" height="36.374"/>
<path style="fill:#FFFFFF;" d="M641.55,554.032l-222.88-94.06l19.668-46.6l222.88,94.06L641.55,554.032z M437.277,452.401
l196.717,83.024l8.617-20.423l-196.717-83.024L437.277,452.401z"/>
</g>
<g>
<rect x="426.295" y="56.081" transform="matrix(0.9213 -0.3888 0.3888 0.9213 13.624 215.8596)" style="fill:#333333;" width="227.719" height="36.374"/>
<path style="fill:#FFFFFF;" d="M438.545,144.598l-19.668-46.6l222.887-94.06l19.667,46.6L438.545,144.598z M437.484,105.568
l8.617,20.423l196.724-83.024l-8.617-20.423L437.484,105.568z"/>
</g>
</g>
<g>
<path style="fill:#333333;" d="M430.774,280.311c0-50.839-32.955-93.895-78.642-109.198V13.262L124.404,165.081H10.54v227.728
h113.864l227.728,151.819V389.51C397.818,374.206,430.774,331.151,430.774,280.311z"/>
<path style="fill:#FFFFFF;" d="M359.23,557.9L122.257,399.908H3.44V157.978h118.816L359.23,0v166.117
c47.245,18.038,78.642,63.308,78.642,114.192s-31.397,96.154-78.642,114.192V557.9z M17.638,385.711h108.917l218.478,145.652
V384.407l4.846-1.622c44.139-14.794,73.796-55.973,73.796-102.476s-29.657-87.682-73.796-102.476l-4.846-1.622V26.538
L126.555,172.176H17.638V385.711z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -85,6 +85,7 @@ function Trigger(hand) {
}
var coolInTimeout = null;
var ignoredEntities = [];
var TELEPORTER_STATES = {
IDLE: 'idle',
@ -239,11 +240,11 @@ function Teleporter() {
// We might hit an invisible entity that is not a seat, so we need to do a second pass.
// * In the second pass we pick against visible entities only.
//
var intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity], false, true);
var intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), false, true);
var teleportLocationType = getTeleportTargetType(intersection);
if (teleportLocationType === TARGET.INVISIBLE) {
intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity], true, true);
intersection = Entities.findRayIntersection(pickRay, true, [], [this.targetEntity].concat(ignoredEntities), true, true);
teleportLocationType = getTeleportTargetType(intersection);
}
@ -513,7 +514,7 @@ function cleanup() {
Script.scriptEnding.connect(cleanup);
var isDisabled = false;
var handleHandMessages = function(channel, message, sender) {
var handleTeleportMessages = function(channel, message, sender) {
var data;
if (sender === MyAvatar.sessionUUID) {
if (channel === 'Hifi-Teleport-Disabler') {
@ -529,12 +530,20 @@ var handleHandMessages = function(channel, message, sender) {
if (message === 'none') {
isDisabled = false;
}
} else if (channel === 'Hifi-Teleport-Ignore-Add' && !Uuid.isNull(message) && ignoredEntities.indexOf(message) === -1) {
ignoredEntities.push(message);
} else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) {
var removeIndex = ignoredEntities.indexOf(message);
if (removeIndex > -1) {
ignoredEntities.splice(removeIndex, 1);
}
}
}
}
Messages.subscribe('Hifi-Teleport-Disabler');
Messages.messageReceived.connect(handleHandMessages);
Messages.subscribe('Hifi-Teleport-Ignore-Add');
Messages.subscribe('Hifi-Teleport-Ignore-Remove');
Messages.messageReceived.connect(handleTeleportMessages);
}()); // END LOCAL_SCOPE

View file

@ -33,13 +33,27 @@ Script.include([
"libraries/gridTool.js",
"libraries/entityList.js",
"particle_explorer/particleExplorerTool.js",
"libraries/lightOverlayManager.js"
"libraries/entityIconOverlayManager.js"
]);
var selectionDisplay = SelectionDisplay;
var selectionManager = SelectionManager;
var lightOverlayManager = new LightOverlayManager();
const PARTICLE_SYSTEM_URL = Script.resolvePath("assets/images/icon-particles.svg");
const POINT_LIGHT_URL = Script.resolvePath("assets/images/icon-point-light.svg");
const SPOT_LIGHT_URL = Script.resolvePath("assets/images/icon-spot-light.svg");
entityIconOverlayManager = new EntityIconOverlayManager(['Light', 'ParticleEffect'], function(entityID) {
var properties = Entities.getEntityProperties(entityID, ['type', 'isSpotlight']);
if (properties.type === 'Light') {
return {
url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL,
}
} else {
return {
url: PARTICLE_SYSTEM_URL,
}
}
});
var cameraManager = new CameraManager();
@ -53,7 +67,45 @@ var entityListTool = new EntityListTool();
selectionManager.addEventListener(function () {
selectionDisplay.updateHandles();
lightOverlayManager.updatePositions();
entityIconOverlayManager.updatePositions();
// Update particle explorer
var needToDestroyParticleExplorer = false;
if (selectionManager.selections.length === 1) {
var selectedEntityID = selectionManager.selections[0];
if (selectedEntityID === selectedParticleEntityID) {
return;
}
var type = Entities.getEntityProperties(selectedEntityID, "type").type;
if (type === "ParticleEffect") {
// Destroy the old particles web view first
particleExplorerTool.destroyWebView();
particleExplorerTool.createWebView();
var properties = Entities.getEntityProperties(selectedEntityID);
var particleData = {
messageType: "particle_settings",
currentProperties: properties
};
selectedParticleEntityID = selectedEntityID;
particleExplorerTool.setActiveParticleEntity(selectedParticleEntityID);
particleExplorerTool.webView.webEventReceived.connect(function (data) {
data = JSON.parse(data);
if (data.messageType === "page_loaded") {
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
}
});
} else {
needToDestroyParticleExplorer = true;
}
} else {
needToDestroyParticleExplorer = true;
}
if (needToDestroyParticleExplorer && selectedParticleEntityID !== null) {
selectedParticleEntityID = null;
particleExplorerTool.destroyWebView();
}
});
const KEY_P = 80; //Key code for letter p used for Parenting hotkey.
@ -82,13 +134,13 @@ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
var MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "Show Lights and Particle Systems in Edit Mode";
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode";
var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode";
var SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE = "showLightsAndParticlesInEditMode";
var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode";
@ -506,7 +558,7 @@ var toolBar = (function () {
toolBar.writeProperty("shown", false);
toolBar.writeProperty("shown", true);
}
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE));
Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
};
@ -571,8 +623,8 @@ function findClickedEntity(event) {
}
var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
var lightResult = lightOverlayManager.findRayIntersection(pickRay);
lightResult.accurate = true;
var iconResult = entityIconOverlayManager.findRayIntersection(pickRay);
iconResult.accurate = true;
if (pickZones) {
Entities.setZonesArePickable(false);
@ -580,18 +632,12 @@ function findClickedEntity(event) {
var result;
if (!entityResult.intersects && !lightResult.intersects) {
return null;
} else if (entityResult.intersects && !lightResult.intersects) {
if (iconResult.intersects) {
result = iconResult;
} else if (entityResult.intersects) {
result = entityResult;
} else if (!entityResult.intersects && lightResult.intersects) {
result = lightResult;
} else {
if (entityResult.distance < lightResult.distance) {
result = entityResult;
} else {
result = lightResult;
}
return null;
}
if (!result.accurate) {
@ -945,18 +991,18 @@ function setupModelMenus() {
});
Menu.addMenuItem({
menuName: "Edit",
menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE,
menuItemName: MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE,
afterItem: MENU_EASE_ON_FOCUS,
isCheckable: true,
isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) === "true",
isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) !== "false",
grouping: "Advanced"
});
Menu.addMenuItem({
menuName: "Edit",
menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE,
afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE,
afterItem: MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE,
isCheckable: true,
isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) === "true",
isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) !== "false",
grouping: "Advanced"
});
@ -987,7 +1033,7 @@ function cleanupModelMenus() {
Menu.removeMenuItem("Edit", MENU_AUTO_FOCUS_ON_SELECT);
Menu.removeMenuItem("Edit", MENU_EASE_ON_FOCUS);
Menu.removeMenuItem("Edit", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
Menu.removeMenuItem("Edit", MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE);
Menu.removeMenuItem("Edit", MENU_SHOW_ZONES_IN_EDIT_MODE);
}
@ -995,7 +1041,7 @@ Script.scriptEnding.connect(function () {
toolBar.setActive(false);
Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT));
Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
Settings.setValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
Settings.setValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE));
Settings.setValue(SETTING_SHOW_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
progressDialog.cleanup();
@ -1184,7 +1230,7 @@ function parentSelectedEntities() {
}
function deleteSelectedEntities() {
if (SelectionManager.hasSelection()) {
selectedParticleEntity = 0;
selectedParticleEntityID = null;
particleExplorerTool.destroyWebView();
SelectionManager.saveProperties();
var savedProperties = [];
@ -1283,8 +1329,8 @@ function handeMenuEvent(menuItem) {
selectAllEtitiesInCurrentSelectionBox(false);
} else if (menuItem === "Select All Entities Touching Box") {
selectAllEtitiesInCurrentSelectionBox(true);
} else if (menuItem === MENU_SHOW_LIGHTS_IN_EDIT_MODE) {
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
} else if (menuItem === MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) {
entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE));
} else if (menuItem === MENU_SHOW_ZONES_IN_EDIT_MODE) {
Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
}
@ -1959,43 +2005,13 @@ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
var propertiesTool = new PropertiesTool();
var particleExplorerTool = new ParticleExplorerTool();
var selectedParticleEntity = 0;
var selectedParticleEntityID = null;
entityListTool.webView.webEventReceived.connect(function (data) {
data = JSON.parse(data);
if(data.type === 'parent') {
if (data.type === 'parent') {
parentSelectedEntities();
} else if(data.type === 'unparent') {
unparentSelectedEntities();
} else if (data.type === "selectionUpdate") {
var ids = data.entityIds;
if (ids.length === 1) {
if (Entities.getEntityProperties(ids[0], "type").type === "ParticleEffect") {
if (JSON.stringify(selectedParticleEntity) === JSON.stringify(ids[0])) {
// This particle entity is already selected, so return
return;
}
// Destroy the old particles web view first
particleExplorerTool.destroyWebView();
particleExplorerTool.createWebView();
var properties = Entities.getEntityProperties(ids[0]);
var particleData = {
messageType: "particle_settings",
currentProperties: properties
};
selectedParticleEntity = ids[0];
particleExplorerTool.setActiveParticleEntity(ids[0]);
particleExplorerTool.webView.webEventReceived.connect(function (data) {
data = JSON.parse(data);
if (data.messageType === "page_loaded") {
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
}
});
} else {
selectedParticleEntity = 0;
particleExplorerTool.destroyWebView();
}
}
}
});

View file

@ -1,9 +1,6 @@
var POINT_LIGHT_URL = "http://s3.amazonaws.com/hifi-public/images/tools/point-light.svg";
var SPOT_LIGHT_URL = "http://s3.amazonaws.com/hifi-public/images/tools/spot-light.svg";
LightOverlayManager = function() {
var self = this;
/* globals EntityIconOverlayManager:true */
EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) {
var visible = false;
// List of all created overlays
@ -22,9 +19,16 @@ LightOverlayManager = function() {
for (var id in entityIDs) {
var entityID = entityIDs[id];
var properties = Entities.getEntityProperties(entityID);
Overlays.editOverlay(entityOverlays[entityID], {
var overlayProperties = {
position: properties.position
});
};
if (getOverlayPropertiesFunc) {
var customProperties = getOverlayPropertiesFunc(entityID, properties);
for (var key in customProperties) {
overlayProperties[key] = customProperties[key];
}
}
Overlays.editOverlay(entityOverlays[entityID], overlayProperties);
}
};
@ -34,7 +38,7 @@ LightOverlayManager = function() {
if (result.intersects) {
for (var id in entityOverlays) {
if (result.overlayID == entityOverlays[id]) {
if (result.overlayID === entityOverlays[id]) {
result.entityID = entityIDs[id];
found = true;
break;
@ -50,7 +54,7 @@ LightOverlayManager = function() {
};
this.setVisible = function(isVisible) {
if (visible != isVisible) {
if (visible !== isVisible) {
visible = isVisible;
for (var id in entityOverlays) {
Overlays.editOverlay(entityOverlays[id], {
@ -62,12 +66,13 @@ LightOverlayManager = function() {
// Allocate or get an unused overlay
function getOverlay() {
if (unusedOverlays.length == 0) {
var overlay = Overlays.addOverlay("image3d", {});
var overlay;
if (unusedOverlays.length === 0) {
overlay = Overlays.addOverlay("image3d", {});
allOverlays.push(overlay);
} else {
var overlay = unusedOverlays.pop();
};
overlay = unusedOverlays.pop();
}
return overlay;
}
@ -79,24 +84,32 @@ LightOverlayManager = function() {
}
function addEntity(entityID) {
var properties = Entities.getEntityProperties(entityID);
if (properties.type == "Light" && !(entityID in entityOverlays)) {
var properties = Entities.getEntityProperties(entityID, ['position', 'type']);
if (entityTypes.indexOf(properties.type) > -1 && !(entityID in entityOverlays)) {
var overlay = getOverlay();
entityOverlays[entityID] = overlay;
entityIDs[entityID] = entityID;
Overlays.editOverlay(overlay, {
var overlayProperties = {
position: properties.position,
url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL,
rotation: Quat.fromPitchYawRollDegrees(0, 0, 270),
visible: visible,
alpha: 0.9,
scale: 0.5,
drawInFront: true,
isFacingAvatar: true,
color: {
red: 255,
green: 255,
blue: 255
}
});
};
if (getOverlayPropertiesFunc) {
var customProperties = getOverlayPropertiesFunc(entityID, properties);
for (var key in customProperties) {
overlayProperties[key] = customProperties[key];
}
}
Overlays.editOverlay(overlay, overlayProperties);
}
}
@ -130,4 +143,4 @@ LightOverlayManager = function() {
Overlays.deleteOverlay(allOverlays[i]);
}
});
};
};

View file

@ -1032,10 +1032,12 @@ SelectionDisplay = (function() {
var pickRay = controllerComputePickRay();
if (pickRay) {
var entityIntersection = Entities.findRayIntersection(pickRay, true);
var iconIntersection = entityIconOverlayManager.findRayIntersection(pickRay);
var overlayIntersection = Overlays.findRayIntersection(pickRay);
if (entityIntersection.intersects &&
if (iconIntersection.intersects) {
selectionManager.setSelections([iconIntersection.entityID]);
} else if (entityIntersection.intersects &&
(!overlayIntersection.intersects || (entityIntersection.distance < overlayIntersection.distance))) {
if (HMD.tabletID === entityIntersection.entityID) {

View file

@ -0,0 +1,80 @@
//
// boppoClownEntity.js
//
// Created by Thijs Wenker on 3/15/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals LookAtTarget */
(function() {
var SFX_PREFIX = 'https://hifi-content.s3-us-west-1.amazonaws.com/caitlyn/production/elBoppo/sfx/';
var CHANNEL_PREFIX = 'io.highfidelity.boppo_server_';
var PUNCH_SOUNDS = [
'punch_1.wav',
'punch_2.wav'
];
var PUNCH_COOLDOWN = 300;
Script.include('lookAtEntity.js');
var createBoppoClownEntity = function() {
var _this,
_entityID,
_boppoUserData,
_lookAtTarget,
_punchSounds = [],
_lastPlayedPunch = {};
var getOwnBoppoUserData = function() {
try {
return JSON.parse(Entities.getEntityProperties(_entityID, ['userData']).userData).Boppo;
} catch (e) {
// e
}
return {};
};
var BoppoClownEntity = function () {
_this = this;
PUNCH_SOUNDS.forEach(function(punch) {
_punchSounds.push(SoundCache.getSound(SFX_PREFIX + punch));
});
};
BoppoClownEntity.prototype = {
preload: function(entityID) {
_entityID = entityID;
_boppoUserData = getOwnBoppoUserData();
_lookAtTarget = new LookAtTarget(_entityID);
},
collisionWithEntity: function(boppoEntity, collidingEntity, collisionInfo) {
if (collisionInfo.type === 0 &&
Entities.getEntityProperties(collidingEntity, ['name']).name.indexOf('Boxing Glove ') === 0) {
if (_lastPlayedPunch[collidingEntity] === undefined ||
Date.now() - _lastPlayedPunch[collidingEntity] > PUNCH_COOLDOWN) {
// If boxing glove detected here:
Messages.sendMessage(CHANNEL_PREFIX + _boppoUserData.gameParentID, 'hit');
_lookAtTarget.lookAtByAction();
var randomPunchIndex = Math.floor(Math.random() * _punchSounds.length);
Audio.playSound(_punchSounds[randomPunchIndex], {
position: collisionInfo.contactPoint
});
_lastPlayedPunch[collidingEntity] = Date.now();
}
}
}
};
return new BoppoClownEntity();
};
return createBoppoClownEntity();
});

View file

@ -0,0 +1,303 @@
//
// boppoServer.js
//
// Created by Thijs Wenker on 3/15/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
var SFX_PREFIX = 'https://hifi-content.s3-us-west-1.amazonaws.com/caitlyn/production/elBoppo/sfx/';
var CLOWN_LAUGHS = [
'clown_laugh_1.wav',
'clown_laugh_2.wav',
'clown_laugh_3.wav',
'clown_laugh_4.wav'
];
var TICK_TOCK_SOUND = 'ticktock%20-%20tock.wav';
var BOXING_RING_BELL_START = 'boxingRingBell.wav';
var BOXING_RING_BELL_END = 'boxingRingBell-end.wav';
var BOPPO_MUSIC = 'boppoMusic.wav';
var CHANNEL_PREFIX = 'io.highfidelity.boppo_server_';
var MESSAGE_HIT = 'hit';
var MESSAGE_ENTER_ZONE = 'enter-zone';
var MESSAGE_UNLOAD_FIX = 'unload-fix';
var DEFAULT_SOUND_VOLUME = 0.6;
// don't set the search radius too high, it might remove boppo's from other nearby instances
var BOPPO_SEARCH_RADIUS = 4.0;
var MILLISECONDS_PER_SECOND = 1000;
// Make sure the entities are loaded at startup (TODO: more solid fix)
var LOAD_TIMEOUT = 5000;
var SECONDS_PER_MINUTE = 60;
var DEFAULT_PLAYTIME = 30; // seconds
var BASE_TEN = 10;
var TICK_TOCK_FROM = 3; // seconds
var COOLDOWN_TIME_MS = MILLISECONDS_PER_SECOND * 3;
var createBoppoServer = function() {
var _this,
_isInitialized = false,
_clownLaughs = [],
_musicInjector,
_music,
_laughingInjector,
_tickTockSound,
_boxingBellRingStart,
_boxingBellRingEnd,
_entityID,
_boppoClownID,
_channel,
_boppoEntities,
_isGameRunning,
_updateInterval,
_timeLeft,
_hits,
_coolDown;
var getOwnBoppoUserData = function() {
try {
return JSON.parse(Entities.getEntityProperties(_entityID, ['userData']).userData).Boppo;
} catch (e) {
// e
}
return {};
};
var updateBoppoEntities = function() {
Entities.getChildrenIDs(_entityID).forEach(function(entityID) {
try {
var userData = JSON.parse(Entities.getEntityProperties(entityID, ['userData']).userData);
if (userData.Boppo.type !== undefined) {
_boppoEntities[userData.Boppo.type] = entityID;
}
} catch (e) {
// e
}
});
};
var clearUntrackedBoppos = function() {
var position = Entities.getEntityProperties(_entityID, ['position']).position;
Entities.findEntities(position, BOPPO_SEARCH_RADIUS).forEach(function(entityID) {
try {
if (JSON.parse(Entities.getEntityProperties(entityID, ['userData']).userData).Boppo.type === 'boppo') {
Entities.deleteEntity(entityID);
}
} catch (e) {
// e
}
});
};
var updateTimerDisplay = function() {
if (_boppoEntities['timer']) {
var secondsString = _timeLeft % SECONDS_PER_MINUTE;
if (secondsString < BASE_TEN) {
secondsString = '0' + secondsString;
}
var minutesString = Math.floor(_timeLeft / SECONDS_PER_MINUTE);
Entities.editEntity(_boppoEntities['timer'], {
text: minutesString + ':' + secondsString
});
}
};
var updateScoreDisplay = function() {
if (_boppoEntities['score']) {
Entities.editEntity(_boppoEntities['score'], {
text: 'SCORE: ' + _hits
});
}
};
var playSoundAtBoxingRing = function(sound, properties) {
var _properties = properties ? properties : {};
if (_properties['volume'] === undefined) {
_properties['volume'] = DEFAULT_SOUND_VOLUME;
}
_properties['position'] = Entities.getEntityProperties(_entityID, ['position']).position;
// play beep
return Audio.playSound(sound, _properties);
};
var onUpdate = function() {
_timeLeft--;
if (_timeLeft > 0 && _timeLeft <= TICK_TOCK_FROM) {
// play beep
playSoundAtBoxingRing(_tickTockSound);
}
if (_timeLeft === 0) {
if (_musicInjector !== undefined && _musicInjector.isPlaying()) {
_musicInjector.stop();
_musicInjector = undefined;
}
playSoundAtBoxingRing(_boxingBellRingEnd);
_isGameRunning = false;
Script.clearInterval(_updateInterval);
_updateInterval = null;
_coolDown = true;
Script.setTimeout(function() {
_coolDown = false;
_this.resetBoppo();
}, COOLDOWN_TIME_MS);
}
updateTimerDisplay();
};
var onMessage = function(channel, message, sender) {
if (channel === _channel) {
if (message === MESSAGE_HIT) {
_this.hit();
} else if (message === MESSAGE_ENTER_ZONE && !_isGameRunning) {
_this.resetBoppo();
} else if (message === MESSAGE_UNLOAD_FIX && _isInitialized) {
_this.unload();
}
}
};
var BoppoServer = function () {
_this = this;
_hits = 0;
_boppoClownID = null;
_coolDown = false;
CLOWN_LAUGHS.forEach(function(clownLaugh) {
_clownLaughs.push(SoundCache.getSound(SFX_PREFIX + clownLaugh));
});
_tickTockSound = SoundCache.getSound(SFX_PREFIX + TICK_TOCK_SOUND);
_boxingBellRingStart = SoundCache.getSound(SFX_PREFIX + BOXING_RING_BELL_START);
_boxingBellRingEnd = SoundCache.getSound(SFX_PREFIX + BOXING_RING_BELL_END);
_music = SoundCache.getSound(SFX_PREFIX + BOPPO_MUSIC);
_boppoEntities = {};
};
BoppoServer.prototype = {
preload: function(entityID) {
_entityID = entityID;
_channel = CHANNEL_PREFIX + entityID;
Messages.sendLocalMessage(_channel, MESSAGE_UNLOAD_FIX);
Script.setTimeout(function() {
clearUntrackedBoppos();
updateBoppoEntities();
Messages.subscribe(_channel);
Messages.messageReceived.connect(onMessage);
_this.resetBoppo();
_isInitialized = true;
}, LOAD_TIMEOUT);
},
resetBoppo: function() {
if (_boppoClownID !== null) {
print('deleting boppo: ' + _boppoClownID);
Entities.deleteEntity(_boppoClownID);
}
var boppoBaseProperties = Entities.getEntityProperties(_entityID, ['position', 'rotation']);
_boppoClownID = Entities.addEntity({
angularDamping: 0.0,
collisionSoundURL: 'https://hifi-content.s3.amazonaws.com/caitlyn/production/elBoppo/51460__andre-rocha-nascimento__basket-ball-01-bounce.wav',
collisionsWillMove: true,
compoundShapeURL: 'https://hifi-content.s3.amazonaws.com/caitlyn/production/elBoppo/bopo_phys.obj',
damping: 1.0,
density: 10000,
dimensions: {
x: 1.2668079137802124,
y: 2.0568051338195801,
z: 0.88563752174377441
},
dynamic: 1.0,
friction: 1.0,
gravity: {
x: 0,
y: -25,
z: 0
},
modelURL: 'https://hifi-content.s3.amazonaws.com/caitlyn/production/elBoppo/elBoppo3_VR.fbx',
name: 'El Boppo the Punching Bag Clown',
registrationPoint: {
x: 0.5,
y: 0,
z: 0.3
},
restitution: 0.99,
rotation: boppoBaseProperties.rotation,
position: Vec3.sum(boppoBaseProperties.position,
Vec3.multiplyQbyV(boppoBaseProperties.rotation, {
x: 0.08666179329156876,
y: -1.5698202848434448,
z: 0.1847127377986908
})),
script: Script.resolvePath('boppoClownEntity.js'),
shapeType: 'compound',
type: 'Model',
userData: JSON.stringify({
lookAt: {
targetID: _boppoEntities['lookAtThis'],
disablePitch: true,
disableYaw: false,
disableRoll: true,
clearDisabledAxis: true,
rotationOffset: { x: 0.0, y: 180.0, z: 0.0}
},
Boppo: {
type: 'boppo',
gameParentID: _entityID
},
grabbableKey: {
grabbable: false
}
})
});
updateBoppoEntities();
_boppoEntities['boppo'] = _boppoClownID;
},
laugh: function() {
if (_laughingInjector !== undefined && _laughingInjector.isPlaying()) {
return;
}
var randomLaughIndex = Math.floor(Math.random() * _clownLaughs.length);
_laughingInjector = Audio.playSound(_clownLaughs[randomLaughIndex], {
position: Entities.getEntityProperties(_boppoClownID, ['position']).position
});
},
hit: function() {
if (_coolDown) {
return;
}
if (!_isGameRunning) {
var boxingRingBoppoData = getOwnBoppoUserData();
_updateInterval = Script.setInterval(onUpdate, MILLISECONDS_PER_SECOND);
_timeLeft = boxingRingBoppoData.playTimeSeconds ? parseInt(boxingRingBoppoData.playTimeSeconds) :
DEFAULT_PLAYTIME;
_isGameRunning = true;
_hits = 0;
playSoundAtBoxingRing(_boxingBellRingStart);
_musicInjector = playSoundAtBoxingRing(_music, {loop: true, volume: 0.6});
}
_hits++;
updateTimerDisplay();
updateScoreDisplay();
_this.laugh();
},
unload: function() {
print('unload called');
if (_updateInterval) {
Script.clearInterval(_updateInterval);
}
Messages.messageReceived.disconnect(onMessage);
Messages.unsubscribe(_channel);
Entities.deleteEntity(_boppoClownID);
print('endOfUnload');
}
};
return new BoppoServer();
};
return createBoppoServer();
});

View file

@ -0,0 +1,154 @@
//
// clownGloveDispenser.js
//
// Created by Thijs Wenker on 8/2/16.
// Copyright 2016 High Fidelity, Inc.
//
// Based on examples/winterSmashUp/targetPractice/shooterPlatform.js
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
var _this = this;
var CHANNEL_PREFIX = 'io.highfidelity.boppo_server_';
var leftBoxingGlove = undefined;
var rightBoxingGlove = undefined;
var inZone = false;
var wearGloves = function() {
leftBoxingGlove = Entities.addEntity({
position: MyAvatar.position,
collisionsWillMove: true,
dimensions: {
x: 0.24890634417533875,
y: 0.28214839100837708,
z: 0.21127720177173615
},
dynamic: true,
gravity: {
x: 0,
y: -9.8,
z: 0
},
modelURL: "https://hifi-content.s3.amazonaws.com/caitlyn/production/elBoppo/LFT_glove_VR3.fbx",
name: "Boxing Glove - Left",
registrationPoint: {
x: 0.5,
y: 0,
z: 0.5
},
shapeType: "simple-hull",
type: "Model",
userData: JSON.stringify({
grabbableKey: {
invertSolidWhileHeld: true
},
wearable: {
joints: {
LeftHand: [
{x: 0, y: 0.0, z: 0.02 },
Quat.fromVec3Degrees({x: 0, y: 0, z: 0})
]
}
}
})
});
Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'left', entityID: leftBoxingGlove}));
// Allows teleporting while glove is wielded
Messages.sendLocalMessage('Hifi-Teleport-Ignore-Add', leftBoxingGlove);
rightBoxingGlove = Entities.addEntity({
position: MyAvatar.position,
collisionsWillMove: true,
dimensions: {
x: 0.24890634417533875,
y: 0.28214839100837708,
z: 0.21127720177173615
},
dynamic: true,
gravity: {
x: 0,
y: -9.8,
z: 0
},
modelURL: "https://hifi-content.s3.amazonaws.com/caitlyn/production/elBoppo/RT_glove_VR2.fbx",
name: "Boxing Glove - Right",
registrationPoint: {
x: 0.5,
y: 0,
z: 0.5
},
shapeType: "simple-hull",
type: "Model",
userData: JSON.stringify({
grabbableKey: {
invertSolidWhileHeld: true
},
wearable: {
joints: {
RightHand: [
{x: 0, y: 0.0, z: 0.02 },
Quat.fromVec3Degrees({x: 0, y: 0, z: 0})
]
}
}
})
});
Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'right', entityID: rightBoxingGlove}));
// Allows teleporting while glove is wielded
Messages.sendLocalMessage('Hifi-Teleport-Ignore-Add', rightBoxingGlove);
};
var cleanUpGloves = function() {
if (leftBoxingGlove !== undefined) {
Entities.deleteEntity(leftBoxingGlove);
leftBoxingGlove = undefined;
}
if (rightBoxingGlove !== undefined) {
Entities.deleteEntity(rightBoxingGlove);
rightBoxingGlove = undefined;
}
};
var wearGlovesIfHMD = function() {
// cleanup your old gloves if they're still there (unlikely)
cleanUpGloves();
if (HMD.active) {
wearGloves();
}
};
_this.preload = function(entityID) {
HMD.displayModeChanged.connect(function() {
if (inZone) {
wearGlovesIfHMD();
}
});
};
_this.unload = function() {
cleanUpGloves();
};
_this.enterEntity = function(entityID) {
inZone = true;
print('entered boxing glove dispenser entity');
wearGlovesIfHMD();
// Reset boppo if game is not running:
var parentID = Entities.getEntityProperties(entityID, ['parentID']).parentID;
Messages.sendMessage(CHANNEL_PREFIX + parentID, 'enter-zone');
};
_this.leaveEntity = function(entityID) {
inZone = false;
cleanUpGloves();
};
_this.unload = _this.leaveEntity;
});

View file

@ -0,0 +1,430 @@
//
// createElBoppo.js
//
// Created by Thijs Wenker on 3/17/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals SCRIPT_IMPORT_PROPERTIES */
var MODELS_PATH = 'https://hifi-content.s3.amazonaws.com/DomainContent/Welcome%20Area/production/models/boxingRing/';
var WANT_CLEANUP_ON_SCRIPT_ENDING = false;
var getScriptPath = function(localPath) {
if (this.isCleanupAndSpawnScript) {
return 'https://hifi-content.s3.amazonaws.com/DomainContent/Welcome%20Area/Scripts/boppo/' + localPath;
}
return Script.resolvePath(localPath);
};
var getCreatePosition = function() {
// can either return position defined by resetScript or avatar position
if (this.isCleanupAndSpawnScript) {
return SCRIPT_IMPORT_PROPERTIES.rootPosition;
}
return Vec3.sum(MyAvatar.position, {x: 1, z: -2});
};
var boxingRing = Entities.addEntity({
dimensions: {
x: 4.0584001541137695,
y: 4.0418000221252441,
z: 3.0490000247955322
},
modelURL: MODELS_PATH + 'assembled/boppoBoxingRingAssembly.fbx',
name: 'Boxing Ring Assembly',
rotation: {
w: 0.9996337890625,
x: -1.52587890625e-05,
y: -0.026230275630950928,
z: -4.57763671875e-05
},
position: getCreatePosition(),
scriptTimestamp: 1489612158459,
serverScripts: getScriptPath('boppoServer.js'),
shapeType: 'static-mesh',
type: 'Model',
userData: JSON.stringify({
Boppo: {
type: 'boxingring',
playTimeSeconds: 15
}
})
});
var boppoEntities = [
{
dimensions: {
x: 0.36947935819625854,
y: 0.25536194443702698,
z: 0.059455446898937225
},
modelURL: MODELS_PATH + 'boxingGameSign/boppoSignFrame.fbx',
parentID: boxingRing,
localPosition: {
x: -1.0251024961471558,
y: 0.51661628484725952,
z: -1.1176263093948364
},
rotation: {
w: 0.996856689453125,
x: 0.013321161270141602,
y: 0.0024566650390625,
z: 0.078049898147583008
},
shapeType: 'box',
type: 'Model'
},
{
dimensions: {
x: 0.33255371451377869,
y: 0.1812121719121933,
z: 0.0099999997764825821
},
lineHeight: 0.125,
name: 'Boxing Ring - High Score Board',
parentID: boxingRing,
localPosition: {
x: -1.0239436626434326,
y: 0.52212876081466675,
z: -1.0971509218215942
},
rotation: {
w: 0.9876401424407959,
x: 0.013046503067016602,
y: 0.0012359619140625,
z: 0.15605401992797852
},
text: '0:00',
textColor: {
blue: 0,
green: 0,
red: 255
},
type: 'Text',
userData: JSON.stringify({
Boppo: {
type: 'timer'
}
})
},
{
dimensions: {
x: 0.50491130352020264,
y: 0.13274604082107544,
z: 0.0099999997764825821
},
lineHeight: 0.090000003576278687,
name: 'Boxing Ring - Score Board',
parentID: boxingRing,
localPosition: {
x: -0.77596306800842285,
y: 0.37797555327415466,
z: -1.0910623073577881
},
rotation: {
w: 0.9518122673034668,
x: 0.004237703513354063,
y: -0.0010041374480351806,
z: 0.30455198884010315
},
text: 'SCORE: 0',
textColor: {
blue: 0,
green: 0,
red: 255
},
type: 'Text',
userData: JSON.stringify({
Boppo: {
type: 'score'
}
})
},
{
dimensions: {
x: 0.58153259754180908,
y: 0.1884911060333252,
z: 0.059455446898937225
},
modelURL: MODELS_PATH + 'boxingGameSign/boppoSignFrame.fbx',
parentID: boxingRing,
localPosition: {
x: -0.78200173377990723,
y: 0.35684797167778015,
z: -1.108180046081543
},
rotation: {
w: 0.97814905643463135,
x: 0.0040436983108520508,
y: -0.0005645751953125,
z: 0.20778214931488037
},
shapeType: 'box',
type: 'Model'
},
{
dimensions: {
x: 4.1867804527282715,
y: 3.5065803527832031,
z: 5.6845207214355469
},
name: 'El Boppo the Clown boxing area & glove maker',
parentID: boxingRing,
localPosition: {
x: -0.012308252975344658,
y: 0.054641719907522202,
z: 0.98782551288604736
},
rotation: {
w: 1,
x: -1.52587890625e-05,
y: -1.52587890625e-05,
z: -1.52587890625e-05
},
script: getScriptPath('clownGloveDispenser.js'),
shapeType: 'box',
type: 'Zone',
visible: false
},
{
color: {
blue: 255,
green: 5,
red: 255
},
dimensions: {
x: 0.20000000298023224,
y: 0.20000000298023224,
z: 0.20000000298023224
},
name: 'LookAtBox',
parentID: boxingRing,
localPosition: {
x: -0.1772226095199585,
y: -1.7072629928588867,
z: 1.3122396469116211
},
rotation: {
w: 0.999969482421875,
x: 1.52587890625e-05,
y: 0.0043793916702270508,
z: 1.52587890625e-05
},
shape: 'Cube',
type: 'Box',
userData: JSON.stringify({
Boppo: {
type: 'lookAtThis'
}
})
},
{
color: {
blue: 209,
green: 157,
red: 209
},
dimensions: {
x: 1.6913000345230103,
y: 1.2124500274658203,
z: 0.2572999894618988
},
name: 'boppoBackBoard',
parentID: boxingRing,
localPosition: {
x: -0.19500596821308136,
y: -1.1044719219207764,
z: -0.55993378162384033
},
rotation: {
w: 0.9807126522064209,
x: -0.19511711597442627,
y: 0.0085297822952270508,
z: 0.0016937255859375
},
shape: 'Cube',
type: 'Box',
visible: false
},
{
color: {
blue: 0,
green: 0,
red: 255
},
dimensions: {
x: 1.8155574798583984,
y: 0.92306196689605713,
z: 0.51203572750091553
},
name: 'boppoBackBoard',
parentID: boxingRing,
localPosition: {
x: -0.11036647111177444,
y: -0.051978692412376404,
z: -0.79054081439971924
},
rotation: {
w: 0.9807431697845459,
x: 0.19505608081817627,
y: 0.0085602998733520508,
z: -0.0017547607421875
},
shape: 'Cube',
type: 'Box',
visible: false
},
{
color: {
blue: 209,
green: 157,
red: 209
},
dimensions: {
x: 1.9941408634185791,
y: 1.2124500274658203,
z: 0.2572999894618988
},
name: 'boppoBackBoard',
localPosition: {
x: 0.69560068845748901,
y: -1.3840068578720093,
z: 0.059689953923225403
},
rotation: {
w: 0.73458456993103027,
x: -0.24113833904266357,
y: -0.56545358896255493,
z: -0.28734266757965088
},
shape: 'Cube',
type: 'Box',
visible: false
},
{
color: {
blue: 82,
green: 82,
red: 82
},
dimensions: {
x: 8.3777303695678711,
y: 0.87573593854904175,
z: 7.9759469032287598
},
parentID: boxingRing,
localPosition: {
x: -0.38302639126777649,
y: -2.121284008026123,
z: 0.3699878454208374
},
rotation: {
w: 0.70711839199066162,
x: -7.62939453125e-05,
y: 0.70705735683441162,
z: -1.52587890625e-05
},
shape: 'Triangle',
type: 'Shape'
},
{
color: {
blue: 209,
green: 157,
red: 209
},
dimensions: {
x: 1.889795184135437,
y: 0.86068248748779297,
z: 0.2572999894618988
},
name: 'boppoBackBoard',
parentID: boxingRing,
localPosition: {
x: -0.95167744159698486,
y: -1.4756947755813599,
z: -0.042313352227210999
},
rotation: {
w: 0.74004733562469482,
x: -0.24461740255355835,
y: 0.56044864654541016,
z: 0.27998781204223633
},
shape: 'Cube',
type: 'Box',
visible: false
},
{
color: {
blue: 0,
green: 0,
red: 255
},
dimensions: {
x: 4.0720257759094238,
y: 0.50657749176025391,
z: 1.4769613742828369
},
name: 'boppo-stepsRamp',
parentID: boxingRing,
localPosition: {
x: -0.002939039608463645,
y: -1.9770187139511108,
z: 2.2165381908416748
},
rotation: {
w: 0.99252307415008545,
x: 0.12184333801269531,
y: -1.52587890625e-05,
z: -1.52587890625e-05
},
shape: 'Cube',
type: 'Box',
visible: false
},
{
color: {
blue: 150,
green: 150,
red: 150
},
cutoff: 90,
dimensions: {
x: 5.2220535278320312,
y: 5.2220535278320312,
z: 5.2220535278320312
},
falloffRadius: 2,
intensity: 15,
name: 'boxing ring light',
parentID: boxingRing,
localPosition: {
x: -1.4094564914703369,
y: -0.36021926999092102,
z: 0.81797939538955688
},
rotation: {
w: 0.9807431697845459,
x: 1.52587890625e-05,
y: -0.19520866870880127,
z: -1.52587890625e-05
},
type: 'Light'
}
];
boppoEntities.forEach(function(entityProperties) {
entityProperties['parentID'] = boxingRing;
Entities.addEntity(entityProperties);
});
if (WANT_CLEANUP_ON_SCRIPT_ENDING) {
Script.scriptEnding.connect(function() {
Entities.deleteEntity(boxingRing);
});
}

View file

@ -0,0 +1,98 @@
//
// lookAtTarget.js
//
// Created by Thijs Wenker on 3/15/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals LookAtTarget:true */
LookAtTarget = function(sourceEntityID) {
/* private variables */
var _this,
_options,
_sourceEntityID,
_sourceEntityProperties,
REQUIRED_PROPERTIES = ['position', 'rotation', 'userData'],
LOOK_AT_TAG = 'lookAtTarget';
LookAtTarget = function(sourceEntityID) {
_this = this;
_sourceEntityID = sourceEntityID;
_this.updateOptions();
};
/* private functions */
var updateEntitySourceProperties = function() {
_sourceEntityProperties = Entities.getEntityProperties(_sourceEntityID, REQUIRED_PROPERTIES);
};
var getUpdatedActionProperties = function() {
return {
targetRotation: _this.getLookAtRotation(),
angularTimeScale: 0.1,
ttl: 10
};
};
var getNewActionProperties = function() {
var newActionProperties = getUpdatedActionProperties();
newActionProperties.tag = LOOK_AT_TAG;
return newActionProperties;
};
LookAtTarget.prototype = {
/* public functions */
updateOptions: function() {
updateEntitySourceProperties();
_options = JSON.parse(_sourceEntityProperties.userData).lookAt;
},
getTargetPosition: function() {
return Entities.getEntityProperties(_options.targetID).position;
},
getLookAtRotation: function() {
_this.updateOptions();
var newRotation = Quat.lookAt(_sourceEntityProperties.position, _this.getTargetPosition(), Vec3.UP);
if (_options.rotationOffset !== undefined) {
newRotation = Quat.multiply(newRotation, Quat.fromVec3Degrees(_options.rotationOffset));
}
if (_options.disablePitch || _options.disableYaw || _options.disablePitch) {
var disabledAxis = _options.clearDisabledAxis ? Vec3.ZERO :
Quat.safeEulerAngles(_sourceEntityProperties.rotation);
var newEulers = Quat.safeEulerAngles(newRotation);
newRotation = Quat.fromVec3Degrees({
x: _options.disablePitch ? disabledAxis.x : newEulers.x,
y: _options.disableYaw ? disabledAxis.y : newEulers.y,
z: _options.disableRoll ? disabledAxis.z : newEulers.z
});
}
return newRotation;
},
lookAtDirectly: function() {
Entities.editEntity(_sourceEntityID, {rotation: _this.getLookAtRotation()});
},
lookAtByAction: function() {
var actionIDs = Entities.getActionIDs(_sourceEntityID);
var actionFound = false;
actionIDs.forEach(function(actionID) {
if (actionFound) {
return;
}
var actionArguments = Entities.getActionArguments(_sourceEntityID, actionID);
if (actionArguments.tag === LOOK_AT_TAG) {
actionFound = true;
Entities.updateAction(_sourceEntityID, actionID, getUpdatedActionProperties());
}
});
if (!actionFound) {
Entities.addAction('spring', _sourceEntityID, getNewActionProperties());
}
}
};
return new LookAtTarget(sourceEntityID);
};