mirror of
https://github.com/overte-org/overte.git
synced 2025-04-29 22:22:37 +02:00
216 lines
7.6 KiB
JavaScript
216 lines
7.6 KiB
JavaScript
// doppleganger-app.js
|
|
//
|
|
// Created by Timothy Dedischew on 04/21/2017.
|
|
// Copyright 2017 High Fidelity, Inc.
|
|
//
|
|
// This Client script creates an instance of a Doppleganger that can be toggled on/off via tablet button.
|
|
// (for more info see doppleganger.js)
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
/* eslint-env commonjs */
|
|
/* global DriveKeys, require:true, console */
|
|
/* eslint-disable comma-dangle */
|
|
|
|
// decomment next line for automatic require cache-busting
|
|
// var require = function require(id) { return Script.require(id + '?'+new Date().getTime().toString(36)); };
|
|
if (typeof require !== 'function') {
|
|
require = Script.require;
|
|
}
|
|
|
|
var VERSION = '0.0.0';
|
|
var WANT_DEBUG = false;
|
|
var DEBUG_MOVE_AS_YOU_MOVE = false;
|
|
var ROTATE_AS_YOU_MOVE = false;
|
|
|
|
log(VERSION);
|
|
|
|
var DopplegangerClass = require('./doppleganger.js'),
|
|
DopplegangerAttachments = require('./doppleganger-attachments.js'),
|
|
DebugControls = require('./doppleganger-debug.js'),
|
|
modelHelper = require('./model-helper.js').modelHelper,
|
|
utils = require('./utils.js');
|
|
|
|
// eslint-disable-next-line camelcase
|
|
var isWebpack = typeof __webpack_require__ === 'function';
|
|
|
|
var buttonConfig = utils.assign({
|
|
text: 'MIRROR',
|
|
}, !isWebpack ? {
|
|
icon: Script.resolvePath('./doppleganger-i.svg'),
|
|
activeIcon: Script.resolvePath('./doppleganger-a.svg'),
|
|
} : {
|
|
icon: require('./doppleganger-i.svg.json'),
|
|
activeIcon: require('./doppleganger-a.svg.json'),
|
|
});
|
|
|
|
var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system'),
|
|
button = tablet.addButton(buttonConfig);
|
|
|
|
Script.scriptEnding.connect(function() {
|
|
tablet.removeButton(button);
|
|
button = null;
|
|
});
|
|
|
|
var doppleganger = new DopplegangerClass({
|
|
avatar: MyAvatar,
|
|
mirrored: false,
|
|
autoUpdate: true,
|
|
type: 'overlay'
|
|
});
|
|
|
|
// add support for displaying regular (non-soft) attachments on the doppleganger
|
|
{
|
|
var RECHECK_ATTACHMENT_MS = 1000;
|
|
var dopplegangerAttachments = new DopplegangerAttachments(doppleganger),
|
|
attachmentInterval = null,
|
|
lastHash = dopplegangerAttachments.getAttachmentsHash();
|
|
|
|
// monitor for attachment changes, but only when the doppleganger is active
|
|
doppleganger.activeChanged.connect(function(active, reason) {
|
|
if (attachmentInterval) {
|
|
Script.clearInterval(attachmentInterval);
|
|
}
|
|
if (active) {
|
|
attachmentInterval = Script.setInterval(checkAttachmentsHash, RECHECK_ATTACHMENT_MS);
|
|
} else {
|
|
attachmentInterval = null;
|
|
}
|
|
});
|
|
function checkAttachmentsHash() {
|
|
var currentHash = dopplegangerAttachments.getAttachmentsHash();
|
|
if (currentHash !== lastHash) {
|
|
lastHash = currentHash;
|
|
debugPrint('app-doppleganger | detect attachment change');
|
|
dopplegangerAttachments.refreshAttachments();
|
|
}
|
|
}
|
|
}
|
|
|
|
// add support for "move as you move"
|
|
{
|
|
var movementKeys = 'W,A,S,D,Up,Down,Right,Left'.split(',');
|
|
var controllerKeys = 'LX,LY,RY'.split(',');
|
|
var translationKeys = Object.keys(DriveKeys).filter(function(p) {
|
|
return /translate/i.test(p);
|
|
});
|
|
var startingPosition;
|
|
|
|
// returns an array of any active driving keys (eg: ['W', 'TRANSLATE_Z'])
|
|
function currentDrivers() {
|
|
return [].concat(
|
|
movementKeys.map(function(key) {
|
|
return Controller.getValue(Controller.Hardware.Keyboard[key]) && key;
|
|
})
|
|
).concat(
|
|
controllerKeys.map(function(key) {
|
|
return Controller.getValue(Controller.Standard[key]) !== 0.0 && key;
|
|
})
|
|
).concat(
|
|
translationKeys.map(function(key) {
|
|
return MyAvatar.getRawDriveKey(DriveKeys[key]) !== 0.0 && key;
|
|
})
|
|
).filter(Boolean);
|
|
}
|
|
|
|
doppleganger.jointsUpdated.connect(function(objectID) {
|
|
var drivers = currentDrivers(),
|
|
isDriving = drivers.length > 0;
|
|
if (isDriving) {
|
|
if (startingPosition) {
|
|
debugPrint('resetting startingPosition since drivers == ', drivers.join('|'));
|
|
startingPosition = null;
|
|
}
|
|
} else if (HMD.active || DEBUG_MOVE_AS_YOU_MOVE) {
|
|
startingPosition = startingPosition || MyAvatar.position;
|
|
var movement = Vec3.subtract(MyAvatar.position, startingPosition);
|
|
startingPosition = MyAvatar.position;
|
|
// Vec3.length(movement) > 0.0001 && Vec3.print('+avatarMovement', movement);
|
|
|
|
// "mirror" the relative translation vector
|
|
movement.x *= -1;
|
|
movement.z *= -1;
|
|
var props = {};
|
|
props.position = doppleganger.position = Vec3.sum(doppleganger.position, movement);
|
|
if (ROTATE_AS_YOU_MOVE) {
|
|
props.rotation = doppleganger.orientation = MyAvatar.orientation;
|
|
}
|
|
modelHelper.editObject(doppleganger.objectID, props);
|
|
}
|
|
});
|
|
}
|
|
|
|
// hide the doppleganger if this client script is unloaded
|
|
Script.scriptEnding.connect(doppleganger, 'stop');
|
|
|
|
// hide the doppleganger if the user switches domains (which might place them arbitrarily far away in world space)
|
|
function onDomainChanged() {
|
|
if (doppleganger.active) {
|
|
doppleganger.stop('domain_changed');
|
|
}
|
|
}
|
|
Window.domainChanged.connect(onDomainChanged);
|
|
Window.domainConnectionRefused.connect(onDomainChanged);
|
|
Script.scriptEnding.connect(function() {
|
|
Window.domainChanged.disconnect(onDomainChanged);
|
|
Window.domainConnectionRefused.disconnect(onDomainChanged);
|
|
});
|
|
|
|
// toggle on/off via tablet button
|
|
button.clicked.connect(doppleganger, 'toggle');
|
|
|
|
// highlight tablet button based on current doppleganger state
|
|
doppleganger.activeChanged.connect(function(active, reason) {
|
|
if (button) {
|
|
button.editProperties({ isActive: active });
|
|
debugPrint('doppleganger.activeChanged', active, reason);
|
|
}
|
|
});
|
|
|
|
// alert the user if there was an error applying their skeletonModelURL
|
|
doppleganger.modelLoaded.connect(function(error, result) {
|
|
if (doppleganger.active && error) {
|
|
Window.alert('doppleganger | ' + error + '\n' + doppleganger.skeletonModelURL);
|
|
}
|
|
});
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// add debug indicators, but only if the user has configured the settings value
|
|
if (Settings.getValue('debug.doppleganger', false)) {
|
|
WANT_DEBUG = WANT_DEBUG || true;
|
|
DopplegangerClass.WANT_DEBUG = WANT_DEBUG;
|
|
DopplegangerAttachments.WANT_DEBUG = WANT_DEBUG;
|
|
new DebugControls(doppleganger);
|
|
}
|
|
|
|
function log() {
|
|
// eslint-disable-next-line no-console
|
|
(typeof console === 'object' ? console.log : print)('app-doppleganger | ' + [].slice.call(arguments).join(' '));
|
|
}
|
|
|
|
function debugPrint() {
|
|
WANT_DEBUG && log.apply(this, arguments);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
UserActivityLogger.logAction('doppleganger_app_load');
|
|
doppleganger.activeChanged.connect(function(active, reason) {
|
|
if (active) {
|
|
UserActivityLogger.logAction('doppleganger_enable');
|
|
} else {
|
|
if (reason === 'stop') {
|
|
// user intentionally toggled the doppleganger
|
|
UserActivityLogger.logAction('doppleganger_disable');
|
|
} else {
|
|
debugPrint('doppleganger stopped:', reason);
|
|
UserActivityLogger.logAction('doppleganger_autodisable', { reason: reason });
|
|
}
|
|
}
|
|
});
|
|
dopplegangerAttachments.attachmentsUpdated.connect(function(attachments) {
|
|
UserActivityLogger.logAction('doppleganger_attachments', { count: attachments.length });
|
|
});
|
|
|