mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 13:12:39 +02:00
Merge branch 'master' into oculusLoginFeature
This commit is contained in:
commit
2859784e17
29 changed files with 529 additions and 119 deletions
|
@ -34,6 +34,8 @@ Item {
|
|||
property bool withSteam: withSteam
|
||||
property string errorString: errorString
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
|
@ -321,6 +323,13 @@ Item {
|
|||
fontSize: completeProfileBody.fontSize
|
||||
fontBold: completeProfileBody.fontBold
|
||||
onClicked: {
|
||||
if (completeProfileBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked cancel on the complete profile screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
|
||||
}
|
||||
}
|
||||
|
@ -340,6 +349,12 @@ Item {
|
|||
fontSize: completeProfileBody.fontSize
|
||||
fontBold: completeProfileBody.fontBold
|
||||
onClicked: {
|
||||
if (completeProfileBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked create profile"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginErrorMessage.visible = false;
|
||||
if (completeProfileBody.withOculus) {
|
||||
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
|
||||
|
@ -459,8 +474,14 @@ Item {
|
|||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded");
|
||||
console.log("Create Succeeded");
|
||||
if (completeProfileBody.withSteam) {
|
||||
if (completeProfileBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created a profile with Steam successfully from the complete profile screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginDialog.loginThroughSteam();
|
||||
}
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false,
|
||||
|
@ -468,6 +489,15 @@ Item {
|
|||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error);
|
||||
if (completeProfileBody.withSteam || completeProfileBody.withOculus) {
|
||||
if (completeProfileBody.loginDialogPoppedUp) {
|
||||
action = completeProfileBody.withSteam ? "Steam" : "Oculus";
|
||||
var data = {
|
||||
"action": "user failed to create a profile with " + action + " from the complete profile screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
if (!completeProfileBody.withOculus) {
|
||||
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
|
||||
"withOculus": completeProfileBody.withOculus });
|
||||
|
|
|
@ -43,6 +43,8 @@ Item {
|
|||
property string errorString: errorString
|
||||
property bool lostFocus: false
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
|
@ -69,6 +71,19 @@ Item {
|
|||
|
||||
function login() {
|
||||
loginDialog.login(emailField.text, passwordField.text);
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data;
|
||||
if (linkAccountBody.linkSteam) {
|
||||
data = {
|
||||
"action": "user linking hifi account with Steam"
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
"action": "user logging in"
|
||||
};
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
|
||||
"withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
|
||||
}
|
||||
|
@ -297,6 +312,13 @@ Item {
|
|||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
onClicked: {
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked cancel at link account screen"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
loginDialog.dismissLoginDialog();
|
||||
}
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
|
||||
"withOculus": linkAccountBody.withOculus, "errorString": "" });
|
||||
}
|
||||
|
@ -314,7 +336,7 @@ Item {
|
|||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
onClicked: {
|
||||
linkAccountBody.login()
|
||||
linkAccountBody.login();
|
||||
}
|
||||
}
|
||||
TextMetrics {
|
||||
|
@ -350,6 +372,12 @@ Item {
|
|||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked can't access account"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
|
@ -378,6 +406,19 @@ Item {
|
|||
linkAccountBody.withSteam = true;
|
||||
loginDialog.loginThroughSteam();
|
||||
}
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data;
|
||||
if (linkAccountBody.withOculus) {
|
||||
data = {
|
||||
"action": "user clicked login through Oculus"
|
||||
};
|
||||
} else if (linkAccountBody.withSteam) {
|
||||
data = {
|
||||
"action": "user clicked login through Steam"
|
||||
};
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
|
||||
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
|
||||
|
@ -445,6 +486,12 @@ Item {
|
|||
linkColor: hifi.colors.blueAccent
|
||||
onLinkActivated: {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked sign up button"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
|
||||
"errorString": "" });
|
||||
}
|
||||
|
@ -472,8 +519,7 @@ Item {
|
|||
fontBold: linkAccountBody.fontBold
|
||||
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
|
||||
onClicked: {
|
||||
if (loginDialog.getLoginDialogPoppedUp()) {
|
||||
console.log("[ENCOURAGELOGINDIALOG]: user dismissed login screen")
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user dismissed login screen"
|
||||
};
|
||||
|
|
|
@ -32,6 +32,8 @@ Item {
|
|||
property bool linkOculus: linkOculus
|
||||
property bool createOculus: createOculus
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
|
@ -64,8 +66,12 @@ Item {
|
|||
running: false;
|
||||
repeat: false;
|
||||
onTriggered: {
|
||||
if (loginDialog.getLoginDialogPoppedUp()) {
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
loginDialog.dismissLoginDialog();
|
||||
var data = {
|
||||
"action": "user logged in successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
root.tryDestroy();
|
||||
}
|
||||
|
@ -114,6 +120,12 @@ Item {
|
|||
loggingInText.x = 0;
|
||||
loggingInText.anchors.centerIn = loggingInHeader;
|
||||
loggedInGlyph.visible = true;
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user logged in with Steam successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
} else if (loggingInBody.withOculus) {
|
||||
// reset the flag.
|
||||
loggingInGlyph.visible = false;
|
||||
|
@ -122,8 +134,21 @@ Item {
|
|||
loggingInText.anchors.centerIn = loggingInHeader;
|
||||
loggedInGlyph.text = hifi.glyphs.oculus;
|
||||
loggedInGlyph.visible = true;
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user logged in with Oculus successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
} else {
|
||||
loggingInText.text = "You are now logged in!";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user logged in successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
}
|
||||
successTimer.start();
|
||||
}
|
||||
|
@ -276,8 +301,23 @@ Item {
|
|||
}
|
||||
onHandleLinkCompleted: {
|
||||
console.log("Link Succeeded");
|
||||
loggingInBody.linkSteam = false;
|
||||
loggingInBody.linkOculus = false;
|
||||
if (loggingInBody.linkSteam) {
|
||||
loggingInBody.linkSteam = false;
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Steam with their hifi account credentials successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
} else if (loggingInBody.linkOculus) {
|
||||
loggingInBody.linkOculus = false;
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Oculus with their hifi account credentials successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
loggingInBody.loadingSuccess();
|
||||
}
|
||||
onHandleLinkFailed: {
|
||||
|
@ -285,7 +325,20 @@ Item {
|
|||
loggingInSpinner.visible = false;
|
||||
if (loggingInBody.linkOculus) {
|
||||
loggingInText.text = "Oculus failed to link";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Oculus unsuccessfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
okButton.visible = true;
|
||||
} else if (loggingInBody.linkSteam){
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Steam unsuccessfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
} else {
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": loggingInBody.linkSteam,
|
||||
"linkOculus": loggingInBody.linkOculus, "errorString": error });
|
||||
|
@ -304,22 +357,53 @@ Item {
|
|||
var errorString = "";
|
||||
if (loggingInBody.linkOculus && loggingInBody.withOculus) {
|
||||
errorString = "Username or password is incorrect.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to link Oculus with their hifi account credentials"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else if (loggingInBody.linkSteam && loggingInBody.withSteam) {
|
||||
errorString = "Username or password is incorrect.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to link Steam with their hifi account credentials"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else if (loggingInBody.withSteam) {
|
||||
errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to authenticate with Steam to log in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else if (loggingInBody.withOculus) {
|
||||
errorString = "Your Oculus account is not connected to an existing High Fidelity account. Please create a new one."
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to authenticate with Oculus to log in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else {
|
||||
errorString = "Username or password is incorrect.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed at logging in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ Item {
|
|||
property string errorString: errorString
|
||||
property bool lostFocus: false
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
|
@ -344,6 +346,12 @@ Item {
|
|||
fontSize: signUpBody.fontSize
|
||||
fontBold: signUpBody.fontBold
|
||||
onClicked: {
|
||||
if (signUpBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked cancel button at sign up screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
|
||||
}
|
||||
}
|
||||
|
@ -362,6 +370,12 @@ Item {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
if (signUpBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user clicked sign up button"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
signUpBody.signup();
|
||||
}
|
||||
}
|
||||
|
@ -416,17 +430,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
z: -2
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: {
|
||||
if (!usernameField.focus && !emailField.focus && !passwordField.focus) {
|
||||
usernameField.focus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
//but rise Tablet's one instead for Tablet interface
|
||||
root.keyboardEnabled = HMD.active;
|
||||
|
@ -455,12 +458,26 @@ Item {
|
|||
onHandleSignupCompleted: {
|
||||
console.log("Sign Up Completed");
|
||||
|
||||
if (signUpBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user signed up successfully"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
loginDialog.login(usernameField.text, passwordField.text);
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "linkSteam": false });
|
||||
}
|
||||
onHandleSignupFailed: {
|
||||
console.log("Sign Up Failed")
|
||||
|
||||
if (signUpBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user signed up unsuccessfully"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
if (errorString !== "") {
|
||||
loginErrorMessage.visible = true;
|
||||
var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n");
|
||||
|
|
|
@ -30,6 +30,8 @@ Item {
|
|||
property bool withSteam: withSteam
|
||||
property bool withOculus: withOculus
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
function create() {
|
||||
mainTextContainer.visible = false
|
||||
if (usernameCollisionBody.withOculus) {
|
||||
|
@ -263,8 +265,20 @@ Item {
|
|||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded");
|
||||
if (usernameCollisionBody.withOculus) {
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created a profile with Oculus successfully in the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginDialog.loginThroughOculus();
|
||||
} else if (usernameCollisionBody.withSteam) {
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created a profile with Steam successfully in the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginDialog.loginThroughSteam();
|
||||
}
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
|
||||
|
@ -272,13 +286,25 @@ Item {
|
|||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error)
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to create account from the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
|
||||
mainTextContainer.visible = true
|
||||
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.");
|
||||
}
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded");
|
||||
if (loginDialog.getLoginDialogPoppedUp()) {
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user logged in successfully from the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
|
||||
loginDialog.dismissLoginDialog();
|
||||
}
|
||||
root.tryDestroy();
|
||||
|
@ -286,6 +312,13 @@ Item {
|
|||
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to log in from the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
mainTextContainer.text = "Login Failed";
|
||||
}
|
||||
|
||||
|
|
|
@ -177,8 +177,9 @@ Rectangle {
|
|||
repeat: true
|
||||
onTriggered: {
|
||||
var currentWearable = getCurrentWearable();
|
||||
var soft = currentWearable ? currentWearable.relayParentJoints : false;
|
||||
var softEnabled = currentWearable ? entityHasAvatarJoints(currentWearable.id) : false;
|
||||
var hasSoft = currentWearable && currentWearable.relayParentJoints !== undefined;
|
||||
var soft = hasSoft ? currentWearable.relayParentJoints : false;
|
||||
var softEnabled = hasSoft ? entityHasAvatarJoints(currentWearable.id) : false;
|
||||
isSoft.set(soft);
|
||||
isSoft.enabled = softEnabled;
|
||||
}
|
||||
|
@ -511,7 +512,7 @@ Rectangle {
|
|||
|
||||
function set(value) {
|
||||
notify = false;
|
||||
checked = value
|
||||
checked = value;
|
||||
notify = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2868,7 +2868,7 @@ void Application::showLoginScreen() {
|
|||
dialogsManager->showLoginDialog();
|
||||
emit loginDialogFocusEnabled();
|
||||
QJsonObject loginData = {};
|
||||
loginData["action"] = "login dialog shown";
|
||||
loginData["action"] = "login dialog popped up";
|
||||
UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData);
|
||||
_window->setWindowTitle("High Fidelity Interface");
|
||||
} else {
|
||||
|
@ -6762,7 +6762,7 @@ void Application::updateWindowTitle() const {
|
|||
DependencyManager::get< MessagesClient >()->sendLocalMessage("Toolbar-DomainChanged", "");
|
||||
}
|
||||
|
||||
void Application::clearDomainOctreeDetails() {
|
||||
void Application::clearDomainOctreeDetails(bool clearAll) {
|
||||
// before we delete all entities get MyAvatar's AvatarEntityData ready
|
||||
getMyAvatar()->prepareAvatarEntityDataForReload();
|
||||
|
||||
|
@ -6781,7 +6781,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
});
|
||||
|
||||
// reset the model renderer
|
||||
getEntities()->clear();
|
||||
clearAll ? getEntities()->clear() : getEntities()->clearNonLocalEntities();
|
||||
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
|
||||
|
@ -6819,7 +6819,7 @@ void Application::goToErrorDomainURL(QUrl errorDomainURL) {
|
|||
void Application::resettingDomain() {
|
||||
_notifiedPacketVersionMismatchThisDomain = false;
|
||||
|
||||
clearDomainOctreeDetails();
|
||||
clearDomainOctreeDetails(false);
|
||||
}
|
||||
|
||||
void Application::nodeAdded(SharedNodePointer node) const {
|
||||
|
@ -6905,7 +6905,7 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "audioMixerKilled");
|
||||
} else if (node->getType() == NodeType::EntityServer) {
|
||||
// we lost an entity server, clear all of the domain octree details
|
||||
clearDomainOctreeDetails();
|
||||
clearDomainOctreeDetails(false);
|
||||
} else if (node->getType() == NodeType::AssetServer) {
|
||||
// asset server going away - check if we have the asset browser showing
|
||||
|
||||
|
|
|
@ -469,7 +469,7 @@ private slots:
|
|||
void onDesktopRootItemCreated(QQuickItem* qmlContext);
|
||||
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
||||
void showDesktop();
|
||||
void clearDomainOctreeDetails();
|
||||
void clearDomainOctreeDetails(bool clearAll = true);
|
||||
void onAboutToQuit();
|
||||
void onPresent(quint32 frameCount);
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
|
|||
QVariantMap asMap = variantProperties.toMap();
|
||||
QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine);
|
||||
EntityItemProperties entityProperties;
|
||||
EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, entityProperties);
|
||||
EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptProperties, entityProperties);
|
||||
|
||||
entityProperties.setParentID(myNodeID);
|
||||
entityProperties.setEntityHostType(entity::HostType::AVATAR);
|
||||
|
@ -151,8 +151,29 @@ void AvatarBookmarks::removeBookmark(const QString& bookmarkName) {
|
|||
|
||||
void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) {
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
myAvatar->removeWearableAvatarEntities();
|
||||
addAvatarEntities(avatarEntities);
|
||||
auto currentAvatarEntities = myAvatar->getAvatarEntityData();
|
||||
std::set<QUuid> newAvatarEntities;
|
||||
|
||||
// Update or add all the new avatar entities
|
||||
for (auto& avatarEntityVariant : avatarEntities) {
|
||||
auto avatarEntityVariantMap = avatarEntityVariant.toMap();
|
||||
auto idItr = avatarEntityVariantMap.find("id");
|
||||
if (idItr != avatarEntityVariantMap.end()) {
|
||||
auto propertiesItr = avatarEntityVariantMap.find("properties");
|
||||
if (propertiesItr != avatarEntityVariantMap.end()) {
|
||||
EntityItemID id = idItr.value().toUuid();
|
||||
newAvatarEntities.insert(id);
|
||||
myAvatar->updateAvatarEntity(id, QJsonDocument::fromVariant(propertiesItr.value()).toBinaryData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any old entities not in the new list
|
||||
for (auto& avatarEntityID : currentAvatarEntities.keys()) {
|
||||
if (newAvatarEntities.find(avatarEntityID) == newAvatarEntities.end()) {
|
||||
myAvatar->removeWornAvatarEntity(avatarEntityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarBookmarks::loadBookmark(const QString& bookmarkName) {
|
||||
|
@ -176,7 +197,7 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) {
|
|||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||
myAvatar->removeWearableAvatarEntities();
|
||||
myAvatar->clearWornAvatarEntities();
|
||||
const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString();
|
||||
myAvatar->useFullAvatarURL(avatarUrl);
|
||||
qCDebug(interfaceapp) << "Avatar On";
|
||||
|
|
|
@ -1610,10 +1610,12 @@ void MyAvatar::handleChangedAvatarEntityData() {
|
|||
skip = true;
|
||||
}
|
||||
});
|
||||
sanitizeAvatarEntityProperties(properties);
|
||||
entityTree->withWriteLock([&] {
|
||||
entityTree->updateEntity(id, properties);
|
||||
});
|
||||
if (!skip) {
|
||||
sanitizeAvatarEntityProperties(properties);
|
||||
entityTree->withWriteLock([&] {
|
||||
entityTree->updateEntity(id, properties);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE cached blobs
|
||||
|
@ -1810,19 +1812,27 @@ void MyAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
|
|||
|
||||
void MyAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) {
|
||||
// NOTE: this is an invokable Script call
|
||||
// TODO: we should handle the case where entityData is corrupt or invalid
|
||||
// BEFORE we store into _cachedAvatarEntityBlobs
|
||||
_needToSaveAvatarEntitySettings = true;
|
||||
bool changed = false;
|
||||
_avatarEntitiesLock.withWriteLock([&] {
|
||||
AvatarEntityMap::iterator itr = _cachedAvatarEntityBlobs.find(entityID);
|
||||
if (itr != _cachedAvatarEntityBlobs.end()) {
|
||||
_entitiesToUpdate.push_back(entityID);
|
||||
itr.value() = entityData;
|
||||
auto data = QJsonDocument::fromBinaryData(entityData);
|
||||
if (data.isEmpty() || data.isNull() || !data.isObject() || data.object().isEmpty()) {
|
||||
qDebug() << "ERROR! Trying to update with invalid avatar entity data. Skipping." << data;
|
||||
} else {
|
||||
_entitiesToAdd.push_back(entityID);
|
||||
_cachedAvatarEntityBlobs.insert(entityID, entityData);
|
||||
auto itr = _cachedAvatarEntityBlobs.find(entityID);
|
||||
if (itr == _cachedAvatarEntityBlobs.end()) {
|
||||
_entitiesToAdd.push_back(entityID);
|
||||
_cachedAvatarEntityBlobs.insert(entityID, entityData);
|
||||
changed = true;
|
||||
} else {
|
||||
_entitiesToUpdate.push_back(entityID);
|
||||
itr.value() = entityData;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
_needToSaveAvatarEntitySettings = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::avatarEntityDataToJson(QJsonObject& root) const {
|
||||
|
@ -2362,50 +2372,36 @@ bool isWearableEntity(const EntityItemPointer& entity) {
|
|||
|| entity->getParentID() == AVATAR_SELF_ID);
|
||||
}
|
||||
|
||||
void MyAvatar::clearAvatarEntities() {
|
||||
void MyAvatar::removeWornAvatarEntity(const EntityItemID& entityID) {
|
||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
});
|
||||
for (const auto& entityID : avatarEntityIDs) {
|
||||
entityTree->withWriteLock([&entityID, &entityTree] {
|
||||
// remove this entity first from the entity tree
|
||||
entityTree->deleteEntity(entityID, true, true);
|
||||
});
|
||||
|
||||
// remove the avatar entity from our internal list
|
||||
// (but indicate it doesn't need to be pulled from the tree)
|
||||
clearAvatarEntity(entityID, false);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::removeWearableAvatarEntities() {
|
||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||
if (entityTree) {
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
});
|
||||
for (const auto& entityID : avatarEntityIDs) {
|
||||
auto entity = entityTree->findEntityByID(entityID);
|
||||
if (entity && isWearableEntity(entity)) {
|
||||
entityTree->withWriteLock([&entityID, &entityTree] {
|
||||
// remove this entity first from the entity tree
|
||||
entityTree->deleteEntity(entityID, true, true);
|
||||
});
|
||||
auto entity = entityTree->findEntityByID(entityID);
|
||||
if (entity && isWearableEntity(entity)) {
|
||||
entityTree->withWriteLock([&entityID, &entityTree] {
|
||||
// remove this entity first from the entity tree
|
||||
entityTree->deleteEntity(entityID, true, true);
|
||||
});
|
||||
|
||||
// remove the avatar entity from our internal list
|
||||
// (but indicate it doesn't need to be pulled from the tree)
|
||||
clearAvatarEntity(entityID, false);
|
||||
}
|
||||
// remove the avatar entity from our internal list
|
||||
// (but indicate it doesn't need to be pulled from the tree)
|
||||
clearAvatarEntity(entityID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::clearWornAvatarEntities() {
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
});
|
||||
for (auto entityID : avatarEntityIDs) {
|
||||
removeWornAvatarEntity(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVariantList MyAvatar::getAvatarEntitiesVariant() {
|
||||
// NOTE: this method is NOT efficient
|
||||
QVariantList avatarEntitiesData;
|
||||
|
@ -2428,6 +2424,7 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
|
|||
desiredProperties += PROP_LOCAL_ROTATION;
|
||||
EntityItemProperties entityProperties = entity->getProperties(desiredProperties);
|
||||
QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_myScriptEngine, entityProperties);
|
||||
avatarEntityData["id"] = entityID;
|
||||
avatarEntityData["properties"] = scriptProperties.toVariant();
|
||||
avatarEntitiesData.append(QVariant(avatarEntityData));
|
||||
}
|
||||
|
@ -2806,8 +2803,8 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData)
|
|||
newEntitiesProperties.push_back(properties);
|
||||
}
|
||||
|
||||
// clear any existing avatar entities
|
||||
clearAvatarEntities();
|
||||
// clear any existing wearables
|
||||
clearWornAvatarEntities();
|
||||
|
||||
for (auto& properties : newEntitiesProperties) {
|
||||
DependencyManager::get<EntityScriptingInterface>()->addEntity(properties, true);
|
||||
|
|
|
@ -970,8 +970,8 @@ public:
|
|||
* @returns {object[]}
|
||||
*/
|
||||
Q_INVOKABLE QVariantList getAvatarEntitiesVariant();
|
||||
void clearAvatarEntities();
|
||||
void removeWearableAvatarEntities();
|
||||
void removeWornAvatarEntity(const EntityItemID& entityID);
|
||||
void clearWornAvatarEntities();
|
||||
|
||||
/**jsdoc
|
||||
* Check whether your avatar is flying or not.
|
||||
|
|
|
@ -2744,23 +2744,28 @@ void AvatarData::setAttachmentsVariant(const QVariantList& variant) {
|
|||
}
|
||||
|
||||
void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& data) {
|
||||
bool changed = false;
|
||||
_avatarEntitiesLock.withWriteLock([&] {
|
||||
PackedAvatarEntityMap::iterator itr = _packedAvatarEntityData.find(entityID);
|
||||
auto itr = _packedAvatarEntityData.find(entityID);
|
||||
if (itr == _packedAvatarEntityData.end()) {
|
||||
if (_packedAvatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) {
|
||||
_packedAvatarEntityData.insert(entityID, data);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
itr.value() = data;
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
|
||||
_avatarEntityDataChanged = true;
|
||||
if (changed) {
|
||||
_avatarEntityDataChanged = true;
|
||||
|
||||
if (_clientTraitsHandler) {
|
||||
// we have a client traits handler, so we need to mark this instanced trait as changed
|
||||
// so that changes will be sent next frame
|
||||
_clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID);
|
||||
if (_clientTraitsHandler) {
|
||||
// we have a client traits handler, so we need to mark this instanced trait as changed
|
||||
// so that changes will be sent next frame
|
||||
_clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -465,8 +465,6 @@ public:
|
|||
|
||||
static const QUrl& defaultFullAvatarModelUrl();
|
||||
|
||||
virtual bool isMyAvatar() const { return false; }
|
||||
|
||||
const QUuid getSessionUUID() const { return getID(); }
|
||||
|
||||
glm::vec3 getHandPosition() const;
|
||||
|
|
|
@ -197,9 +197,57 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
|||
});
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::stopNonLocalEntityScripts() {
|
||||
leaveNonLocalEntities();
|
||||
// unload and stop the engine
|
||||
if (_entitiesScriptEngine) {
|
||||
QList<EntityItemID> entitiesWithEntityScripts = _entitiesScriptEngine->getListOfEntityScriptIDs();
|
||||
|
||||
foreach (const EntityItemID& entityID, entitiesWithEntityScripts) {
|
||||
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
|
||||
|
||||
if (entityItem) {
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clearNonLocalEntities() {
|
||||
stopNonLocalEntityScripts();
|
||||
|
||||
std::unordered_map<EntityItemID, EntityRendererPointer> savedEntities;
|
||||
// remove all entities from the scene
|
||||
_space->clear();
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
render::Transaction transaction;
|
||||
for (const auto& entry : _entitiesInScene) {
|
||||
const auto& renderer = entry.second;
|
||||
const EntityItemPointer& entityItem = renderer->getEntity();
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
renderer->removeFromScene(scene, transaction);
|
||||
} else {
|
||||
savedEntities[entry.first] = entry.second;
|
||||
}
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
|
||||
_renderablesToUpdate = savedEntities;
|
||||
_entitiesInScene = savedEntities;
|
||||
|
||||
_layeredZones.clearNonLocalLayeredZones();
|
||||
|
||||
OctreeProcessor::clearNonLocalEntities();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clear() {
|
||||
leaveAllEntities();
|
||||
|
||||
// unload and stop the engine
|
||||
if (_entitiesScriptEngine) {
|
||||
// do this here (instead of in deleter) to avoid marshalling unload signals back to this thread
|
||||
|
@ -211,8 +259,8 @@ void EntityTreeRenderer::clear() {
|
|||
if (_wantScripts && !_shuttingDown) {
|
||||
resetEntitiesScriptEngine();
|
||||
}
|
||||
|
||||
// remove all entities from the scene
|
||||
|
||||
_space->clear();
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
|
@ -507,8 +555,7 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityIt
|
|||
auto entityTree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
||||
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
|
||||
entityTree->evalEntitiesInSphere(_avatarPosition, radius,
|
||||
PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES)), entityIDs);
|
||||
entityTree->evalEntitiesInSphere(_avatarPosition, radius, PickFilter(), entityIDs);
|
||||
|
||||
LayeredZones oldLayeredZones(std::move(_layeredZones));
|
||||
_layeredZones.clear();
|
||||
|
@ -614,6 +661,26 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
return didUpdate;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveNonLocalEntities() {
|
||||
if (_tree && !_shuttingDown) {
|
||||
QVector<EntityItemID> currentLocalEntitiesInside;
|
||||
foreach (const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
emit leaveEntity(entityID);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
}
|
||||
} else {
|
||||
currentLocalEntitiesInside.push_back(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
_currentEntitiesInside = currentLocalEntitiesInside;
|
||||
forceRecheckEntities();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveAllEntities() {
|
||||
if (_tree && !_shuttingDown) {
|
||||
|
||||
|
@ -1136,6 +1203,29 @@ EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::clearNonLocalLayeredZones() {
|
||||
std::set<LayeredZone> localLayeredZones;
|
||||
std::map<QUuid, iterator> newMap;
|
||||
|
||||
for (auto iter = begin(); iter != end(); iter++) {
|
||||
LayeredZone layeredZone = *iter;
|
||||
|
||||
if (layeredZone.zone->isLocalEntity()) {
|
||||
bool success;
|
||||
iterator it;
|
||||
std::tie(it, success) = localLayeredZones.insert(layeredZone);
|
||||
|
||||
if (success) {
|
||||
newMap.emplace(layeredZone.id, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<LayeredZone>::operator=(localLayeredZones);
|
||||
_map = newMap;
|
||||
_skyboxLayer = empty() ? end() : begin();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::clear() {
|
||||
std::set<LayeredZone>::clear();
|
||||
_map.clear();
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
virtual void init() override;
|
||||
|
||||
/// clears the tree
|
||||
virtual void clearNonLocalEntities() override;
|
||||
virtual void clear() override;
|
||||
|
||||
/// reloads the entity scripts, calling unload and preload
|
||||
|
@ -161,6 +162,7 @@ private:
|
|||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyLayeredZones();
|
||||
void stopNonLocalEntityScripts();
|
||||
|
||||
void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false);
|
||||
|
||||
|
@ -169,6 +171,7 @@ private:
|
|||
|
||||
QScriptValueList createEntityArgs(const EntityItemID& entityID);
|
||||
bool checkEnterLeaveEntities();
|
||||
void leaveNonLocalEntities();
|
||||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
|
@ -219,6 +222,7 @@ private:
|
|||
LayeredZones& operator=(LayeredZones&&) = delete;
|
||||
|
||||
void clear();
|
||||
void clearNonLocalLayeredZones();
|
||||
std::pair<iterator, bool> insert(const LayeredZone& layer);
|
||||
void update(std::shared_ptr<ZoneEntityItem> zone);
|
||||
bool contains(const LayeredZones& other);
|
||||
|
|
|
@ -4616,14 +4616,14 @@ bool EntityItemProperties::blobToProperties(QScriptEngine& scriptEngine, const Q
|
|||
// DANGER: this method is NOT efficient.
|
||||
// begin recipe for converting unfortunately-formatted-binary-blob to EntityItemProperties
|
||||
QJsonDocument jsonProperties = QJsonDocument::fromBinaryData(blob);
|
||||
if (!jsonProperties.isObject()) {
|
||||
if (jsonProperties.isEmpty() || jsonProperties.isNull() || !jsonProperties.isObject() || jsonProperties.object().isEmpty()) {
|
||||
qCDebug(entities) << "bad avatarEntityData json" << QString(blob.toHex());
|
||||
return false;
|
||||
}
|
||||
QVariant variant = jsonProperties.toVariant();
|
||||
QVariantMap variantMap = variant.toMap();
|
||||
QScriptValue scriptValue = variantMapToScriptValue(variantMap, scriptEngine);
|
||||
EntityItemPropertiesFromScriptValueHonorReadOnly(scriptValue, properties);
|
||||
EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptValue, properties);
|
||||
// end recipe
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -986,7 +986,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
|
|||
shouldSendDeleteToServer = false;
|
||||
} else {
|
||||
// only delete local entities, server entities will round trip through the server filters
|
||||
if (entity->isAvatarEntity() || _entityTree->isServerlessMode()) {
|
||||
if (!entity->isDomainEntity() || _entityTree->isServerlessMode()) {
|
||||
shouldSendDeleteToServer = false;
|
||||
_entityTree->deleteEntity(entityID);
|
||||
|
||||
|
|
|
@ -70,6 +70,49 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) {
|
|||
return std::static_pointer_cast<OctreeElement>(newElement);
|
||||
}
|
||||
|
||||
void EntityTree::eraseNonLocalEntities() {
|
||||
emit clearingEntities();
|
||||
|
||||
if (_simulation) {
|
||||
// This will clear all entities host types including local entities, because local entities
|
||||
// are not in the physics simulation
|
||||
_simulation->clearEntities();
|
||||
}
|
||||
_staleProxies.clear();
|
||||
QHash<EntityItemID, EntityItemPointer> localMap;
|
||||
localMap.swap(_entityMap);
|
||||
QHash<EntityItemID, EntityItemPointer> savedEntities;
|
||||
this->withWriteLock([&] {
|
||||
foreach(EntityItemPointer entity, localMap) {
|
||||
EntityTreeElementPointer element = entity->getElement();
|
||||
if (element) {
|
||||
element->cleanupNonLocalEntities();
|
||||
}
|
||||
|
||||
if (entity->isLocalEntity()) {
|
||||
savedEntities[entity->getEntityItemID()] = entity;
|
||||
}
|
||||
}
|
||||
});
|
||||
localMap.clear();
|
||||
_entityMap = savedEntities;
|
||||
|
||||
resetClientEditStats();
|
||||
clearDeletedEntities();
|
||||
|
||||
{
|
||||
QWriteLocker locker(&_needsParentFixupLock);
|
||||
QVector<EntityItemWeakPointer> localEntitiesNeedsParentFixup;
|
||||
|
||||
foreach (EntityItemWeakPointer entityItem, _needsParentFixup) {
|
||||
if (!entityItem.expired() && entityItem.lock()->isLocalEntity()) {
|
||||
localEntitiesNeedsParentFixup.push_back(entityItem);
|
||||
}
|
||||
}
|
||||
|
||||
_needsParentFixup = localEntitiesNeedsParentFixup;
|
||||
}
|
||||
}
|
||||
void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
||||
emit clearingEntities();
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ public:
|
|||
return std::static_pointer_cast<EntityTreeElement>(_rootElement);
|
||||
}
|
||||
|
||||
|
||||
virtual void eraseNonLocalEntities() override;
|
||||
virtual void eraseAllOctreeElements(bool createNewRoot = true) override;
|
||||
|
||||
virtual void readBitstreamToTree(const unsigned char* bitstream,
|
||||
|
|
|
@ -683,6 +683,23 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI
|
|||
return foundEntity;
|
||||
}
|
||||
|
||||
void EntityTreeElement::cleanupNonLocalEntities() {
|
||||
withWriteLock([&] {
|
||||
EntityItems savedEntities;
|
||||
foreach(EntityItemPointer entity, _entityItems) {
|
||||
if (!entity->isLocalEntity()) {
|
||||
entity->preDelete();
|
||||
entity->_element = NULL;
|
||||
} else {
|
||||
savedEntities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
_entityItems = savedEntities;
|
||||
});
|
||||
bumpChangedContent();
|
||||
}
|
||||
|
||||
void EntityTreeElement::cleanupEntities() {
|
||||
withWriteLock([&] {
|
||||
foreach(EntityItemPointer entity, _entityItems) {
|
||||
|
|
|
@ -189,6 +189,7 @@ public:
|
|||
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
|
||||
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
void cleanupNonLocalEntities();
|
||||
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
|
||||
bool removeEntityItem(EntityItemPointer entity, bool deletion = false);
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
|
||||
OctreeElementPointer getRoot() { return _rootElement; }
|
||||
|
||||
virtual void eraseNonLocalEntities() { _isDirty = true; };
|
||||
virtual void eraseAllOctreeElements(bool createNewRoot = true);
|
||||
|
||||
virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
|
|
|
@ -51,15 +51,15 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
|
||||
bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showTimingDetails, "OctreeProcessor::processDatagram()", showTimingDetails);
|
||||
|
||||
|
||||
if (message.getType() == getExpectedPacketType()) {
|
||||
PerformanceWarning warn(showTimingDetails, "OctreeProcessor::processDatagram expected PacketType", showTimingDetails);
|
||||
// if we are getting inbound packets, then our tree is also viewing, and we should remember that fact.
|
||||
_tree->setIsViewing(true);
|
||||
|
||||
|
||||
OCTREE_PACKET_FLAGS flags;
|
||||
message.readPrimitive(&flags);
|
||||
|
||||
|
||||
OCTREE_PACKET_SEQUENCE sequence;
|
||||
message.readPrimitive(&sequence);
|
||||
|
||||
|
@ -68,7 +68,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
|
||||
bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT);
|
||||
bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT);
|
||||
|
||||
|
||||
OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
|
||||
qint64 clockSkew = sourceNode ? sourceNode->getClockSkewUsec() : 0;
|
||||
qint64 flightTime = arrivedAt - sentAt + clockSkew;
|
||||
|
@ -79,27 +79,27 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
qCDebug(octree) << "OctreeProcessor::processDatagram() ... "
|
||||
"Got Packet Section color:" << packetIsColored <<
|
||||
"compressed:" << packetIsCompressed <<
|
||||
"sequence: " << sequence <<
|
||||
"sequence: " << sequence <<
|
||||
"flight: " << flightTime << " usec" <<
|
||||
"size:" << message.getSize() <<
|
||||
"data:" << message.getBytesLeftToRead();
|
||||
}
|
||||
|
||||
|
||||
_packetsInLastWindow++;
|
||||
|
||||
|
||||
int elementsPerPacket = 0;
|
||||
int entitiesPerPacket = 0;
|
||||
|
||||
|
||||
quint64 totalWaitingForLock = 0;
|
||||
quint64 totalUncompress = 0;
|
||||
quint64 totalReadBitsteam = 0;
|
||||
|
||||
const QUuid& sourceUUID = sourceNode->getUUID();
|
||||
|
||||
|
||||
int subsection = 1;
|
||||
|
||||
|
||||
bool error = false;
|
||||
|
||||
|
||||
while (message.getBytesLeftToRead() > 0 && !error) {
|
||||
if (packetIsCompressed) {
|
||||
if (message.getBytesLeftToRead() > (qint64) sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) {
|
||||
|
@ -111,7 +111,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
} else {
|
||||
sectionLength = message.getBytesLeftToRead();
|
||||
}
|
||||
|
||||
|
||||
if (sectionLength) {
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL,
|
||||
|
@ -149,7 +149,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
qCDebug(octree) << "OctreeProcessor::processDatagram() ******* END _tree->readBitstreamToTree()...";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// seek forwards in packet
|
||||
message.seek(message.getPosition() + sectionLength);
|
||||
|
||||
|
@ -172,13 +172,13 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
_waitLockPerPacket.updateAverage(totalWaitingForLock);
|
||||
_uncompressPerPacket.updateAverage(totalUncompress);
|
||||
_readBitstreamPerPacket.updateAverage(totalReadBitsteam);
|
||||
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
if (_lastWindowAt == 0) {
|
||||
_lastWindowAt = now;
|
||||
}
|
||||
quint64 sinceLastWindow = now - _lastWindowAt;
|
||||
|
||||
|
||||
if (sinceLastWindow > USECS_PER_SECOND) {
|
||||
float packetsPerSecondInWindow = (float)_packetsInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND);
|
||||
float elementsPerSecondInWindow = (float)_elementsInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND);
|
||||
|
@ -197,6 +197,14 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void OctreeProcessor::clearNonLocalEntities() {
|
||||
if (_tree) {
|
||||
_tree->withWriteLock([&] {
|
||||
_tree->eraseNonLocalEntities();
|
||||
});
|
||||
}
|
||||
}
|
||||
void OctreeProcessor::clear() {
|
||||
if (_tree) {
|
||||
_tree->withWriteLock([&] {
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
virtual void init();
|
||||
|
||||
/// clears the tree
|
||||
virtual void clearNonLocalEntities();
|
||||
virtual void clear();
|
||||
|
||||
float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); }
|
||||
|
|
|
@ -2407,6 +2407,11 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR
|
|||
}
|
||||
}
|
||||
|
||||
QList<EntityItemID> ScriptEngine::getListOfEntityScriptIDs() {
|
||||
QReadLocker locker{ &_entityScriptsLock };
|
||||
return _entityScripts.keys();
|
||||
}
|
||||
|
||||
void ScriptEngine::unloadAllEntityScripts() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
|
|
|
@ -145,6 +145,9 @@ public:
|
|||
|
||||
QString getFilename() const;
|
||||
|
||||
|
||||
QList<EntityItemID> getListOfEntityScriptIDs();
|
||||
|
||||
/**jsdoc
|
||||
* Stop the current script.
|
||||
* @function Script.stop
|
||||
|
|
|
@ -108,7 +108,8 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (parent && parent->getID() == parentID) {
|
||||
if (parent && (parent->getID() == parentID ||
|
||||
(parentID == AVATAR_SELF_ID && parent->isMyAvatar()))) {
|
||||
// parent pointer is up-to-date
|
||||
if (!_parentKnowsMe) {
|
||||
SpatialParentTree* parentTree = parent->getParentTree();
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
virtual const QUuid getParentID() const;
|
||||
virtual void setParentID(const QUuid& parentID);
|
||||
|
||||
virtual bool isMyAvatar() const { return false; }
|
||||
|
||||
virtual quint16 getParentJointIndex() const { return _parentJointIndex; }
|
||||
virtual void setParentJointIndex(quint16 parentJointIndex);
|
||||
|
||||
|
|
|
@ -70,9 +70,9 @@ function getMyAvatarSettings() {
|
|||
}
|
||||
}
|
||||
|
||||
function updateAvatarWearables(avatar, callback) {
|
||||
function updateAvatarWearables(avatar, callback, wearablesOverride) {
|
||||
executeLater(function() {
|
||||
var wearables = getMyAvatarWearables();
|
||||
var wearables = wearablesOverride ? wearablesOverride : getMyAvatarWearables();
|
||||
avatar[ENTRY_AVATAR_ENTITIES] = wearables;
|
||||
|
||||
sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables})
|
||||
|
@ -210,7 +210,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
|||
break;
|
||||
case 'adjustWearable':
|
||||
if(message.properties.localRotationAngles) {
|
||||
message.properties.localRotation = Quat.fromVec3Degrees(message.properties.localRotationAngles)
|
||||
message.properties.localRotation = Quat.fromVec3Degrees(message.properties.localRotationAngles);
|
||||
}
|
||||
|
||||
Entities.editEntity(message.entityID, message.properties);
|
||||
|
@ -235,7 +235,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
|||
// revert changes using snapshot of wearables
|
||||
if(currentAvatarWearablesBackup !== null) {
|
||||
AvatarBookmarks.updateAvatarEntities(currentAvatarWearablesBackup);
|
||||
updateAvatarWearables(currentAvatar);
|
||||
updateAvatarWearables(currentAvatar, null, currentAvatarWearablesBackup);
|
||||
}
|
||||
} else {
|
||||
sendToQml({'method' : 'updateAvatarInBookmarks'});
|
||||
|
|
Loading…
Reference in a new issue