mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 01:22:25 +02:00
Minimal working version for avatar's client
Also merge of Wayne's proof-of-concept
This commit is contained in:
parent
c03839e49f
commit
de97af5c02
10 changed files with 481 additions and 29 deletions
|
@ -368,9 +368,10 @@ void AvatarMixer::manageIdentityData(const SharedNodePointer& node) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool sendIdentity = false;
|
||||
MixerAvatar& avatar = nodeData->getAvatar();
|
||||
bool sendIdentity = avatar.needsIdentityUpdate();
|
||||
if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) {
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
MixerAvatar& avatar = nodeData->getAvatar();
|
||||
const QString& existingBaseDisplayName = nodeData->getAvatar().getSessionDisplayName();
|
||||
if (!existingBaseDisplayName.isEmpty()) {
|
||||
SessionDisplayName existingDisplayName { existingBaseDisplayName };
|
||||
|
@ -415,10 +416,11 @@ void AvatarMixer::manageIdentityData(const SharedNodePointer& node) {
|
|||
sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name or avatar.
|
||||
// since this packet includes a change to either the skeleton model URL or the display name
|
||||
// it needs a new sequence number
|
||||
nodeData->getAvatar().pushIdentitySequenceNumber();
|
||||
avatar.pushIdentitySequenceNumber();
|
||||
|
||||
// tell node whose name changed about its new session display name or avatar.
|
||||
sendIdentityPacket(nodeData, node);
|
||||
avatar.clearIdentityUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QJSonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QCryptographicHash>
|
||||
#include <QApplication>
|
||||
|
||||
#include <ResourceManager.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
|
@ -78,6 +79,7 @@ void MixerAvatar::fstRequestComplete() {
|
|||
} else {
|
||||
_avatarFSTContents = fstRequest->getData();
|
||||
_verifyState = kReceivedFST;
|
||||
_pendingEvent = true;
|
||||
}
|
||||
_avatarRequest->deleteLater();
|
||||
_avatarRequest = nullptr;
|
||||
|
@ -156,12 +158,31 @@ QByteArray MixerAvatar::canonicalJson(const QString fstFile) {
|
|||
return jsonDocCertifiedItems.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
void MixerAvatar::processCertifyEvents() {
|
||||
void MixerAvatar::ownerRequestComplete() {
|
||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||
if (_verifyState != kReceivedFST && _verifyState != kOwnerResponse && _verifyState != kChallengeResponse && _verifyState != kRequestingOwner) {
|
||||
QNetworkReply* networkReply = static_cast<QNetworkReply*>(QObject::sender());
|
||||
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
_dynamicMarketResponse = networkReply->readAll();
|
||||
_verifyState = kOwnerResponse;
|
||||
_pendingEvent = true;
|
||||
} else {
|
||||
auto jsonData = QJsonDocument::fromJson(networkReply->readAll())["data"];
|
||||
if (!jsonData.isUndefined() && !jsonData.toObject()["message"].isUndefined()) {
|
||||
qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << ":"
|
||||
<< jsonData.toObject()["message"].toString();
|
||||
_verifyState = kError;
|
||||
}
|
||||
}
|
||||
networkReply->deleteLater();
|
||||
}
|
||||
|
||||
void MixerAvatar::processCertifyEvents() {
|
||||
if (!_pendingEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||
switch (_verifyState) {
|
||||
|
||||
case kReceivedFST:
|
||||
|
@ -185,24 +206,10 @@ void MixerAvatar::processCertifyEvents() {
|
|||
request["certificate_id"] = _certificateIdFromFST;
|
||||
_verifyState = kRequestingOwner;
|
||||
QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
|
||||
//networkReply->setParent(this);
|
||||
connect(networkReply, &QNetworkReply::readyRead, [this, networkReply]() {
|
||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
_dynamicMarketResponse = networkReply->readAll();
|
||||
_verifyState = kOwnerResponse;
|
||||
} else {
|
||||
auto jsonData = QJsonDocument::fromJson(networkReply->readAll())["data"];
|
||||
if (!jsonData.isUndefined() && !jsonData.toObject()["message"].isUndefined()) {
|
||||
qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << ":"
|
||||
<< jsonData.toObject()["message"].toString();
|
||||
_verifyState = kError;
|
||||
}
|
||||
}
|
||||
networkReply->deleteLater();
|
||||
});
|
||||
connect(networkReply, &QNetworkReply::finished, this, &MixerAvatar::ownerRequestComplete);
|
||||
} else {
|
||||
_verifyState = kVerificationFailedPending;
|
||||
_verifyState = kVerificationFailed;
|
||||
_pendingEvent = false;
|
||||
qCDebug(avatars) << "Avatar" << getDisplayName() << "FAILED static certification";
|
||||
}
|
||||
break;
|
||||
|
@ -244,6 +251,7 @@ void MixerAvatar::processCertifyEvents() {
|
|||
"message:" << responseJson["message"].toString();
|
||||
_verifyState = kError;
|
||||
}
|
||||
_pendingEvent = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -266,19 +274,19 @@ void MixerAvatar::processCertifyEvents() {
|
|||
|
||||
bool challengeResult = EntityItemProperties::verifySignature(_ownerPublicKey, _challengeNonceHash,
|
||||
QByteArray::fromBase64(signedNonce));
|
||||
_verifyState = challengeResult ? kVerificationSucceeded : kVerificationFailedPending;
|
||||
if (_verifyState == kVerificationFailedPending) {
|
||||
_verifyState = challengeResult ? kVerificationSucceeded : kVerificationFailed;
|
||||
_needsIdentityUpdate = true;
|
||||
if (_verifyState == kVerificationFailed) {
|
||||
qCDebug(avatars) << "Dynamic verification FAILED for " << getDisplayName() << getSessionUUID();
|
||||
} else {
|
||||
qCDebug(avatars) << "Dynamic verification SUCCEEDED for " << getDisplayName() << getSessionUUID();
|
||||
}
|
||||
|
||||
_pendingEvent = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case kRequestingOwner:
|
||||
{
|
||||
certifyLocker.unlock();
|
||||
{ // Qt networking done on this thread:
|
||||
QCoreApplication::processEvents();
|
||||
break;
|
||||
}
|
||||
|
@ -307,6 +315,7 @@ void MixerAvatar::sendOwnerChallenge() {
|
|||
_challengeTimeout.setInterval(CHALLENGE_TIMEOUT_MS);
|
||||
_challengeTimeout.connect(&_challengeTimeout, &QTimer::timeout, [this]() {
|
||||
_verifyState = kVerificationFailed;
|
||||
_needsIdentityUpdate = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -318,5 +327,6 @@ void MixerAvatar::handleChallengeResponse(ReceivedMessage * response) {
|
|||
_challengeTimeout.stop();
|
||||
_challengeResponse = response->readAll();
|
||||
_verifyState = kChallengeResponse;
|
||||
_pendingEvent = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,15 @@ public:
|
|||
void setNeedsHeroCheck(bool needsHeroCheck = true) { _needsHeroCheck = needsHeroCheck; }
|
||||
|
||||
void fetchAvatarFST();
|
||||
virtual bool isCertifyFailed() const override { return _verifyState == kVerificationFailed || _verifyState == kVerificationFailedPending; }
|
||||
virtual bool isCertifyFailed() const override { return _verifyState == kVerificationFailed; }
|
||||
bool needsIdentityUpdate() const { return _needsIdentityUpdate; }
|
||||
void clearIdentityUpdate() { _needsIdentityUpdate = false; }
|
||||
|
||||
|
||||
//bool isPendingCertifyFailed() const { return _verifyState == kVerificationFailedPending; }
|
||||
//void advanceCertifyFailed() {
|
||||
// if (isPendingCertifyFailed()) { _verifyState = kVerificationFailed; }
|
||||
//}
|
||||
void processCertifyEvents();
|
||||
void handleChallengeResponse(ReceivedMessage * response);
|
||||
|
||||
|
@ -34,10 +42,11 @@ private:
|
|||
|
||||
// Avatar certification/verification:
|
||||
enum VerifyState { kNoncertified, kRequestingFST, kReceivedFST, kStaticValidation, kRequestingOwner, kOwnerResponse,
|
||||
kChallengeClient, kChallengeResponse, kVerified, kVerificationFailedPending, kVerificationFailed,
|
||||
kChallengeClient, kChallengeResponse, kVerified, kVerificationFailed,
|
||||
kVerificationSucceeded, kError };
|
||||
Q_ENUM(VerifyState);
|
||||
VerifyState _verifyState { kNoncertified };
|
||||
std::atomic<bool> _pendingEvent { false };
|
||||
QMutex _avatarCertifyLock;
|
||||
ResourceRequest* _avatarRequest { nullptr };
|
||||
QString _marketplaceIdFromURL;
|
||||
|
@ -51,6 +60,7 @@ private:
|
|||
QByteArray _challengeNonceHash;
|
||||
QByteArray _challengeResponse;
|
||||
QTimer _challengeTimeout;
|
||||
bool _needsIdentityUpdate { false };
|
||||
|
||||
bool generateFSTHash();
|
||||
bool validateFSTHash(const QString& publicKey);
|
||||
|
@ -59,6 +69,7 @@ private:
|
|||
|
||||
private slots:
|
||||
void fstRequestComplete();
|
||||
void ownerRequestComplete();
|
||||
};
|
||||
|
||||
using MixerAvatarSharedPointer = std::shared_ptr<MixerAvatar>;
|
||||
|
|
BIN
interface/resources/images/AvatarTheftBanner.png
Normal file
BIN
interface/resources/images/AvatarTheftBanner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
70
interface/resources/qml/AvatarTheft.qml
Normal file
70
interface/resources/qml/AvatarTheft.qml
Normal file
|
@ -0,0 +1,70 @@
|
|||
import QtQuick 2.7
|
||||
import stylesUit 1.0 as HifiStylesUit
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
|
||||
Rectangle {
|
||||
color: "black"
|
||||
height: 480
|
||||
width: 720
|
||||
|
||||
readonly property string avatarTheftEntityName: "hifi-avatar-theft-banner";
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: displayMessage;
|
||||
text: "The avatar you're using is registered to another user.";
|
||||
size: 20;
|
||||
color: "white";
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 0.1 * parent.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
HifiStylesUit.ShortcutText {
|
||||
id: gotoShortcut;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 0.4 * parent.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
font.family: "Raleway"
|
||||
font.pixelSize: 20
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
linkColor: hifi.colors.blueAccent
|
||||
text: "<a href='https://fake.link'>Click here to change your avatar and dismiss this banner.</a>"
|
||||
onLinkActivated: {
|
||||
AddressManager.handleLookupString("hifi://BodyMart");
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: contactText;
|
||||
text: "If you own this avatar, please contact"
|
||||
size: 20;
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0.15 * parent.height
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
}
|
||||
|
||||
HifiStylesUit.ShortcutText {
|
||||
id: gotoShortcut;
|
||||
anchors.top: contactText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
font.family: "Raleway"
|
||||
font.pixelSize: 20
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
linkColor: hifi.colors.blueAccent
|
||||
text: "<a href='mailto:support@highfidelity.com'>Click here to change your avatar and dismiss this banner.</a>"
|
||||
onLinkActivated: {
|
||||
HiFiAbout.openUrl("mailto:support@highfidelity.com");
|
||||
}
|
||||
}
|
||||
}
|
67
interface/resources/qml/AvatarTheftBanner.qml
Normal file
67
interface/resources/qml/AvatarTheftBanner.qml
Normal file
|
@ -0,0 +1,67 @@
|
|||
import QtQuick 2.7
|
||||
import stylesUit 1.0 as HifiStylesUit
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
|
||||
Rectangle {
|
||||
color: "black"
|
||||
|
||||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: displayMessage;
|
||||
text: "The avatar you're using is registered to another user.";
|
||||
size: 20;
|
||||
color: "white";
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 0.1 * parent.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
HifiStylesUit.ShortcutText {
|
||||
id: gotoShortcut;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 0.4 * parent.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
font.family: "Raleway"
|
||||
font.pixelSize: 20
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
linkColor: hifi.colors.blueAccent
|
||||
text: "<a href='https://fake.link'>Click here to change your avatar and dismiss this banner.</a>"
|
||||
onLinkActivated: {
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
tablet.loadQMLSource("hifi/AvatarApp.qml");
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: contactText;
|
||||
text: "If you own this avatar, please contact"
|
||||
size: 20;
|
||||
color: "white"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0.15 * parent.height
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
}
|
||||
|
||||
HifiStylesUit.ShortcutText {
|
||||
id: email;
|
||||
anchors.top: contactText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: (parent.width - width) / 2
|
||||
font.family: "Raleway"
|
||||
font.pixelSize: 20
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
linkColor: hifi.colors.blueAccent
|
||||
text: "<a href='mailto:support@highfidelity.com'>support@highfidelity.com.</a>"
|
||||
}
|
||||
}
|
139
interface/resources/qml/AvatarTheftSettings.qml
Normal file
139
interface/resources/qml/AvatarTheftSettings.qml
Normal file
|
@ -0,0 +1,139 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import stylesUit 1.0
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
|
||||
Rectangle {
|
||||
id: root;
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
signal sendToScript(var message);
|
||||
function emitSendToScript(message) {
|
||||
sendToScript(message);
|
||||
}
|
||||
|
||||
function fromScript(message) {
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: title;
|
||||
color: hifi.colors.white;
|
||||
text: qsTr("Avatar Theft Entity position")
|
||||
size: 20
|
||||
font.bold: true
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
leftMargin: (parent.width - width) / 2
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: xSlider
|
||||
anchors {
|
||||
top: title.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
label: "X OFFSET: " + value.toFixed(2);
|
||||
maximumValue: 1.0
|
||||
minimumValue: -1.0
|
||||
stepSize: 0.05
|
||||
value: 0.0
|
||||
width: 300
|
||||
onValueChanged: {
|
||||
emitSendToScript({
|
||||
"method": "reposition",
|
||||
"x": value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: ySlider
|
||||
anchors {
|
||||
top: xSlider.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
label: "Y OFFSET: " + value.toFixed(2);
|
||||
maximumValue: 1.0
|
||||
minimumValue: -1.0
|
||||
stepSize: 0.05
|
||||
value: 0.0
|
||||
width: 300
|
||||
onValueChanged: {
|
||||
emitSendToScript({
|
||||
"method": "reposition",
|
||||
"y": value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: zSlider
|
||||
anchors {
|
||||
top: ySlider.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
label: "Z OFFSET: " + value.toFixed(2);
|
||||
maximumValue: 0.0
|
||||
minimumValue: -2.0
|
||||
stepSize: 0.05
|
||||
value: -1.0
|
||||
width: 300
|
||||
onValueChanged: {
|
||||
emitSendToScript({
|
||||
"method": "reposition",
|
||||
"z": value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: setVisibleButton;
|
||||
text: setVisible ? "SET INVISIBLE" : "SET VISIBLE";
|
||||
width: 300;
|
||||
property bool setVisible: true;
|
||||
anchors {
|
||||
top: zSlider.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
onClicked: {
|
||||
setVisible = !setVisible;
|
||||
emitSendToScript({
|
||||
"method": "setVisible",
|
||||
"visible": setVisible
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: printButton;
|
||||
text: "PRINT POSITIONS";
|
||||
width: 300;
|
||||
anchors {
|
||||
top: setVisibleButton.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
onClicked: {
|
||||
emitSendToScript({
|
||||
"method": "print",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3368,6 +3368,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
|
|||
surfaceContext->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
|
||||
|
||||
if (setAdditionalContextProperties) {
|
||||
qDebug() << "setting additional context properties!";
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto flags = tabletScriptingInterface->getFlags();
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "MyAvatar.h"
|
||||
#include "DebugDraw.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
#include "ui/AvatarCertifyBanner.h"
|
||||
|
||||
// 50 times per second - target is 45hz, but this helps account for any small deviations
|
||||
// in the update loop - this also results in ~30hz when in desktop mode which is essentially
|
||||
|
@ -176,6 +177,13 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
|||
_lastSendAvatarDataTime = now;
|
||||
_myAvatarSendRate.increment();
|
||||
}
|
||||
|
||||
static AvatarCertifyBanner theftBanner;
|
||||
if (_myAvatar->isCertifyFailed()) {
|
||||
theftBanner.show(_myAvatar->getSessionUUID(), _myAvatar->getJointIndex("_CAMERA_MATRIX"));
|
||||
} else {
|
||||
theftBanner.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
144
scripts/developer/tests/avatarTheftPrototype.js
Normal file
144
scripts/developer/tests/avatarTheftPrototype.js
Normal file
|
@ -0,0 +1,144 @@
|
|||
"use strict";
|
||||
|
||||
(function() {
|
||||
|
||||
var appUi = Script.require("appUi");
|
||||
var ui;
|
||||
|
||||
var AVATAR_THEFT_BANNER_IMAGE = Script.resourcesPath() + "images/AvatarTheftBanner.png";
|
||||
var AVATAR_THEFT_SETTINGS_QML = Script.resourcesPath() + "qml/AvatarTheftSettings.qml";
|
||||
var button;
|
||||
var theftBanner = null;
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var onAvatarBanner = false;
|
||||
var THEFT_BANNER_DIMENSIONS = {x: 1.0, y: 1.0, z: 0.3};
|
||||
|
||||
function createEntities() {
|
||||
//if (HMD.active) {
|
||||
var render = tablet.tabletShown ? "world" : "front";
|
||||
var pos = tablet.tabletShown ? { x: 0.0, y: 0.0, z: -1.8 } : { x: 0.0, y: 0.0, z: -0.7 };
|
||||
var dimensionMultiplier = tablet.tabletShown ? 2.6 : 1;
|
||||
var props = {
|
||||
type: "Image",
|
||||
imageURL: AVATAR_THEFT_BANNER_IMAGE,
|
||||
name: "hifi-avatar-theft-banner",
|
||||
parentID: MyAvatar.SELF_ID,
|
||||
parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
|
||||
localPosition: pos,
|
||||
dimensions: {x: THEFT_BANNER_DIMENSIONS.x * dimensionMultiplier, y: THEFT_BANNER_DIMENSIONS.y * dimensionMultiplier},
|
||||
renderLayer: render,
|
||||
userData: {
|
||||
grabbable: false
|
||||
},
|
||||
visible: true
|
||||
};
|
||||
/* var props = {*/
|
||||
//type: "Web",
|
||||
//name: "hifi-avatar-theft-banner",
|
||||
//sourceUrl: AVATAR_THEFT_BANNER_QML,
|
||||
//parentID: MyAvatar.SELF_ID,
|
||||
//parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
|
||||
//localPosition: { x: 0.0, y: 0.0, z: -1.0 },
|
||||
//dimensions: THEFT_BANNER_DIMENSIONS,
|
||||
//drawInFront: true,
|
||||
//userData: {
|
||||
//grabbable: false
|
||||
//},
|
||||
//visible: true
|
||||
/*};*/
|
||||
if (theftBanner) {
|
||||
Entities.deleteEntity(theftBanner);
|
||||
}
|
||||
theftBanner = Entities.addEntity(props, "local");
|
||||
Window.copyToClipboard(theftBanner);
|
||||
console.log("created entity");
|
||||
//} else {
|
||||
//}
|
||||
}
|
||||
|
||||
function fromQml(message) {
|
||||
if (message.method === "reposition") {
|
||||
var theftBannerLocalPosition = Entities.getEntityProperties(theftBanner).localPosition;
|
||||
var newTheftBannerLocalPosition;
|
||||
if (message.x !== undefined) {
|
||||
newTheftBannerLocalPosition = { x: -((THEFT_BANNER_DIMENSIONS.x) / 2) + message.x, y: theftBannerLocalPosition.y, z: theftBannerLocalPosition.z };
|
||||
} else if (message.y !== undefined) {
|
||||
newtheftBannerLocalPosition = { x: theftBannerLocalPosition.x, y: message.y, z: theftBannerLocalPosition.z };
|
||||
} else if (message.z !== undefined) {
|
||||
newtheftBannerLocalPosition = { x: theftBannerLocalPosition.x, y: theftBannerLocalPosition.y, z: message.z };
|
||||
}
|
||||
var theftBannerProps = {
|
||||
localPosition: newtheftBannerLocalPosition
|
||||
};
|
||||
|
||||
Entities.editEntity(theftBanner, theftBannerProps);
|
||||
} else if (message.method === "setVisible") {
|
||||
if (message.visible !== undefined) {
|
||||
var props = {
|
||||
visible: message.visible
|
||||
};
|
||||
Entities.editEntity(theftBannerEntity, props);
|
||||
}
|
||||
} else if (message.method === "print") {
|
||||
// prints the local position into the hifi log.
|
||||
var theftBannerLocalPosition = Entities.getEntityProperties(theftBannerEntity).localPosition;
|
||||
console.log("theft banner local position is at " + JSON.stringify(theftBannerLocalPosition));
|
||||
}
|
||||
};
|
||||
|
||||
var cleanup = function () {
|
||||
if (theftBanner) {
|
||||
Entities.deleteEntity(theftBanner);
|
||||
}
|
||||
};
|
||||
|
||||
function setup() {
|
||||
ui = new appUi({
|
||||
buttonName: "THEFT",
|
||||
home: AVATAR_THEFT_SETTINGS_QML,
|
||||
onMessage: fromQml,
|
||||
onOpened: createEntities,
|
||||
onClosed: cleanup,
|
||||
normalButton: "icons/tablet-icons/edit-i.svg",
|
||||
activeButton: "icons/tablet-icons/edit-a.svg",
|
||||
});
|
||||
};
|
||||
|
||||
setup();
|
||||
|
||||
Entities.mousePressOnEntity.connect(function (entityID, event) {
|
||||
if (entityID === theftBanner && theftBanner){
|
||||
tablet.loadQMLSource(Script.resourcesPath() + "qml/hifi/AvatarApp.qml");
|
||||
}
|
||||
})
|
||||
|
||||
tablet.isTabletShownChanged.connect(function () {
|
||||
if (theftBanner) {
|
||||
if (tablet.tabletShown) {
|
||||
Entities.editEntity(theftBanner, {
|
||||
dimensions: THEFT_BANNER_DIMENSIONS,
|
||||
localPosition: { x: 0.0, y: 0.0, z: -0.7 },
|
||||
renderLayer: "world"
|
||||
});
|
||||
} else {
|
||||
Entities.editEntity(theftBanner, {
|
||||
localPosition: { x: 0.0, y: 0.0, z: -1.8 },
|
||||
dimensions: {x: THEFT_BANNER_DIMENSIONS.x * 2.6, y: THEFT_BANNER_DIMENSIONS.y * 2.6},
|
||||
renderLayer: "front"
|
||||
});
|
||||
}
|
||||
console.log(Entities.getEntityProperties(theftBanner).renderLayer);
|
||||
}
|
||||
})
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
location.hostChanged.connect(function (){
|
||||
if (theftBanner) {
|
||||
Entities.editEntity(theftBanner, {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
}());
|
Loading…
Reference in a new issue