mirror of
https://github.com/overte-org/overte.git
synced 2025-07-24 09:03:54 +02:00
merge from upstream
This commit is contained in:
commit
cffe4551dd
10 changed files with 701 additions and 66 deletions
|
@ -18,17 +18,13 @@
|
||||||
|
|
||||||
class EntityNodeData : public OctreeQueryNode {
|
class EntityNodeData : public OctreeQueryNode {
|
||||||
public:
|
public:
|
||||||
EntityNodeData() :
|
|
||||||
OctreeQueryNode(),
|
|
||||||
_lastDeletedEntitiesSentAt(0) { }
|
|
||||||
|
|
||||||
virtual PacketType getMyPacketType() const { return PacketType::EntityData; }
|
virtual PacketType getMyPacketType() const { return PacketType::EntityData; }
|
||||||
|
|
||||||
quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; }
|
quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; }
|
||||||
void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; }
|
void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint64 _lastDeletedEntitiesSentAt;
|
quint64 _lastDeletedEntitiesSentAt { usecTimestampNow() };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityNodeData_h
|
#endif // hifi_EntityNodeData_h
|
||||||
|
|
|
@ -82,9 +82,15 @@ bool EntityServer::hasSpecialPacketsToSend(const SharedNodePointer& node) {
|
||||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||||
if (nodeData) {
|
if (nodeData) {
|
||||||
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||||
|
|
||||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||||
shouldSendDeletedEntities = tree->hasEntitiesDeletedSince(deletedEntitiesSentAt);
|
shouldSendDeletedEntities = tree->hasEntitiesDeletedSince(deletedEntitiesSentAt);
|
||||||
|
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
if (shouldSendDeletedEntities) {
|
||||||
|
int elapsed = usecTimestampNow() - deletedEntitiesSentAt;
|
||||||
|
qDebug() << "shouldSendDeletedEntities to node:" << node->getUUID() << "deletedEntitiesSentAt:" << deletedEntitiesSentAt << "elapsed:" << elapsed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldSendDeletedEntities;
|
return shouldSendDeletedEntities;
|
||||||
|
@ -97,7 +103,6 @@ int EntityServer::sendSpecialPackets(const SharedNodePointer& node, OctreeQueryN
|
||||||
if (nodeData) {
|
if (nodeData) {
|
||||||
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||||
quint64 deletePacketSentAt = usecTimestampNow();
|
quint64 deletePacketSentAt = usecTimestampNow();
|
||||||
|
|
||||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||||
bool hasMoreToSend = true;
|
bool hasMoreToSend = true;
|
||||||
|
|
||||||
|
@ -118,6 +123,13 @@ int EntityServer::sendSpecialPackets(const SharedNodePointer& node, OctreeQueryN
|
||||||
nodeData->setLastDeletedEntitiesSentAt(deletePacketSentAt);
|
nodeData->setLastDeletedEntitiesSentAt(deletePacketSentAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
if (packetsSent > 0) {
|
||||||
|
qDebug() << "EntityServer::sendSpecialPackets() sent " << packetsSent << "special packets of "
|
||||||
|
<< totalBytes << " total bytes to node:" << node->getUUID();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: caller is expecting a packetLength, what if we send more than one packet??
|
// TODO: caller is expecting a packetLength, what if we send more than one packet??
|
||||||
return totalBytes;
|
return totalBytes;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +139,6 @@ void EntityServer::pruneDeletedEntities() {
|
||||||
if (tree->hasAnyDeletedEntities()) {
|
if (tree->hasAnyDeletedEntities()) {
|
||||||
|
|
||||||
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
|
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
|
||||||
|
|
||||||
DependencyManager::get<NodeList>()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
|
DependencyManager::get<NodeList>()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
|
||||||
if (node->getLinkedData()) {
|
if (node->getLinkedData()) {
|
||||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||||
|
@ -137,7 +148,6 @@ void EntityServer::pruneDeletedEntities() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tree->forgetEntitiesDeletedBefore(earliestLastDeletedEntitiesSent);
|
tree->forgetEntitiesDeletedBefore(earliestLastDeletedEntitiesSent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -570,14 +570,12 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
||||||
OctreeServer::trackInsideTime((float)elapsedInsideUsecs);
|
OctreeServer::trackInsideTime((float)elapsedInsideUsecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (somethingToSend && _myServer->wantsVerboseDebug()) {
|
||||||
if (somethingToSend) {
|
qCDebug(otree) << "Hit PPS Limit, packetsSentThisInterval =" << packetsSentThisInterval
|
||||||
qCDebug(octree) << "Hit PPS Limit, packetsSentThisInterval =" << packetsSentThisInterval
|
<< " maxPacketsPerInterval = " << maxPacketsPerInterval
|
||||||
<< " maxPacketsPerInterval = " << maxPacketsPerInterval
|
<< " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval;
|
||||||
<< " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Here's where we can/should allow the server to send other data...
|
// Here's where we can/should allow the server to send other data...
|
||||||
// send the environment packet
|
// send the environment packet
|
||||||
// TODO: should we turn this into a while loop to better handle sending multiple special packets
|
// TODO: should we turn this into a while loop to better handle sending multiple special packets
|
||||||
|
|
|
@ -17,17 +17,21 @@ var NAMES = new Array("Craig", "Clement", "Jeff"); // ACs names ordered by IDs (
|
||||||
|
|
||||||
// Those variables MUST be common to every scripts
|
// Those variables MUST be common to every scripts
|
||||||
var controlEntitySize = 0.25;
|
var controlEntitySize = 0.25;
|
||||||
var controlEntityPosition = { x: 2000 , y: 0, z: 0 };
|
var controlEntityPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
// Script. DO NOT MODIFY BEYOND THIS LINE.
|
// Script. DO NOT MODIFY BEYOND THIS LINE.
|
||||||
Script.include("../libraries/toolBars.js");
|
Script.include("../libraries/toolBars.js");
|
||||||
|
|
||||||
|
var clip_url = null;
|
||||||
|
var input_text = null;
|
||||||
|
|
||||||
var DO_NOTHING = 0;
|
var DO_NOTHING = 0;
|
||||||
var PLAY = 1;
|
var PLAY = 1;
|
||||||
var PLAY_LOOP = 2;
|
var PLAY_LOOP = 2;
|
||||||
var STOP = 3;
|
var STOP = 3;
|
||||||
var SHOW = 4;
|
var SHOW = 4;
|
||||||
var HIDE = 5;
|
var HIDE = 5;
|
||||||
|
var LOAD = 6;
|
||||||
|
|
||||||
var COLORS = [];
|
var COLORS = [];
|
||||||
COLORS[PLAY] = { red: PLAY, green: 0, blue: 0 };
|
COLORS[PLAY] = { red: PLAY, green: 0, blue: 0 };
|
||||||
|
@ -35,6 +39,7 @@ COLORS[PLAY_LOOP] = { red: PLAY_LOOP, green: 0, blue: 0 };
|
||||||
COLORS[STOP] = { red: STOP, green: 0, blue: 0 };
|
COLORS[STOP] = { red: STOP, green: 0, blue: 0 };
|
||||||
COLORS[SHOW] = { red: SHOW, green: 0, blue: 0 };
|
COLORS[SHOW] = { red: SHOW, green: 0, blue: 0 };
|
||||||
COLORS[HIDE] = { red: HIDE, green: 0, blue: 0 };
|
COLORS[HIDE] = { red: HIDE, green: 0, blue: 0 };
|
||||||
|
COLORS[LOAD] = { red: LOAD, green: 0, blue: 0 };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,6 +58,7 @@ var onOffIcon = new Array();
|
||||||
var playIcon = new Array();
|
var playIcon = new Array();
|
||||||
var playLoopIcon = new Array();
|
var playLoopIcon = new Array();
|
||||||
var stopIcon = new Array();
|
var stopIcon = new Array();
|
||||||
|
var loadIcon = new Array();
|
||||||
setupToolBars();
|
setupToolBars();
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,6 +110,14 @@ function setupToolBars() {
|
||||||
alpha: ALPHA_OFF,
|
alpha: ALPHA_OFF,
|
||||||
visible: true
|
visible: true
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
loadIcon[i] = toolBars[i].addTool({
|
||||||
|
imageURL: TOOL_ICON_URL + "recording-upload.svg",
|
||||||
|
width: Tool.IMAGE_WIDTH,
|
||||||
|
height: Tool.IMAGE_HEIGHT,
|
||||||
|
alpha: ALPHA_OFF,
|
||||||
|
visible: true
|
||||||
|
}, false);
|
||||||
|
|
||||||
nameOverlays.push(Overlays.addOverlay("text", {
|
nameOverlays.push(Overlays.addOverlay("text", {
|
||||||
backgroundColor: { red: 0, green: 0, blue: 0 },
|
backgroundColor: { red: 0, green: 0, blue: 0 },
|
||||||
|
@ -129,11 +143,13 @@ function sendCommand(id, action) {
|
||||||
toolBars[id].setAlpha(ALPHA_ON, playIcon[id]);
|
toolBars[id].setAlpha(ALPHA_ON, playIcon[id]);
|
||||||
toolBars[id].setAlpha(ALPHA_ON, playLoopIcon[id]);
|
toolBars[id].setAlpha(ALPHA_ON, playLoopIcon[id]);
|
||||||
toolBars[id].setAlpha(ALPHA_ON, stopIcon[id]);
|
toolBars[id].setAlpha(ALPHA_ON, stopIcon[id]);
|
||||||
|
toolBars[id].setAlpha(ALPHA_ON, loadIcon[id]);
|
||||||
} else if (action === HIDE) {
|
} else if (action === HIDE) {
|
||||||
toolBars[id].selectTool(onOffIcon[id], true);
|
toolBars[id].selectTool(onOffIcon[id], true);
|
||||||
toolBars[id].setAlpha(ALPHA_OFF, playIcon[id]);
|
toolBars[id].setAlpha(ALPHA_OFF, playIcon[id]);
|
||||||
toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]);
|
toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]);
|
||||||
toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]);
|
toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]);
|
||||||
|
toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]);
|
||||||
} else if (toolBars[id].toolSelected(onOffIcon[id])) {
|
} else if (toolBars[id].toolSelected(onOffIcon[id])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -148,6 +164,8 @@ function sendCommand(id, action) {
|
||||||
var position = { x: controlEntityPosition.x + id * controlEntitySize,
|
var position = { x: controlEntityPosition.x + id * controlEntitySize,
|
||||||
y: controlEntityPosition.y, z: controlEntityPosition.z };
|
y: controlEntityPosition.y, z: controlEntityPosition.z };
|
||||||
Entities.addEntity({
|
Entities.addEntity({
|
||||||
|
name: "Actor Controller",
|
||||||
|
userData: clip_url,
|
||||||
type: "Box",
|
type: "Box",
|
||||||
position: position,
|
position: position,
|
||||||
dimensions: { x: controlEntitySize, y: controlEntitySize, z: controlEntitySize },
|
dimensions: { x: controlEntitySize, y: controlEntitySize, z: controlEntitySize },
|
||||||
|
@ -173,6 +191,8 @@ function mousePressEvent(event) {
|
||||||
sendCommand(i, PLAY_LOOP);
|
sendCommand(i, PLAY_LOOP);
|
||||||
} else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
} else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
sendCommand(i, STOP);
|
sendCommand(i, STOP);
|
||||||
|
} else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
|
sendCommand(i, LOAD);
|
||||||
} else {
|
} else {
|
||||||
// Check individual controls
|
// Check individual controls
|
||||||
for (i = 0; i < NUM_AC; i++) {
|
for (i = 0; i < NUM_AC; i++) {
|
||||||
|
@ -188,6 +208,12 @@ function mousePressEvent(event) {
|
||||||
sendCommand(i, PLAY_LOOP);
|
sendCommand(i, PLAY_LOOP);
|
||||||
} else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
} else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
sendCommand(i, STOP);
|
sendCommand(i, STOP);
|
||||||
|
} else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
|
input_text = Window.prompt("Insert the url of the clip: ","");
|
||||||
|
if(!(input_text === "" || input_text === null)){
|
||||||
|
clip_url = input_text;
|
||||||
|
sendCommand(i, LOAD);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -231,4 +257,4 @@ Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
||||||
moveUI();
|
moveUI();
|
|
@ -9,10 +9,9 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
|
||||||
|
|
||||||
// Set the following variables to the values needed
|
// Set the following variables to the values needed
|
||||||
var filename = "/Users/clement/Desktop/recording.hfr";
|
var clip_url = null;
|
||||||
var playFromCurrentLocation = true;
|
var playFromCurrentLocation = true;
|
||||||
var useDisplayName = true;
|
var useDisplayName = true;
|
||||||
var useAttachments = true;
|
var useAttachments = true;
|
||||||
|
@ -21,8 +20,6 @@ var useAvatarModel = true;
|
||||||
// ID of the agent. Two agents can't have the same ID.
|
// ID of the agent. Two agents can't have the same ID.
|
||||||
var id = 0;
|
var id = 0;
|
||||||
|
|
||||||
// Set avatar model URL
|
|
||||||
Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/e21c0b95-e502-4d15-8c41-ea2fc40f1125/3585ddf674869a67d31d5964f7b52de1.fst?1427169998";
|
|
||||||
// Set position/orientation/scale here if playFromCurrentLocation is true
|
// Set position/orientation/scale here if playFromCurrentLocation is true
|
||||||
Avatar.position = { x:1, y: 1, z: 1 };
|
Avatar.position = { x:1, y: 1, z: 1 };
|
||||||
Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||||
|
@ -30,7 +27,7 @@ Avatar.scale = 1.0;
|
||||||
|
|
||||||
// Those variables MUST be common to every scripts
|
// Those variables MUST be common to every scripts
|
||||||
var controlEntitySize = 0.25;
|
var controlEntitySize = 0.25;
|
||||||
var controlEntityPosition = { x: 2000, y: 0, z: 0 };
|
var controlEntityPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
// Script. DO NOT MODIFY BEYOND THIS LINE.
|
// Script. DO NOT MODIFY BEYOND THIS LINE.
|
||||||
var DO_NOTHING = 0;
|
var DO_NOTHING = 0;
|
||||||
|
@ -39,6 +36,7 @@ var PLAY_LOOP = 2;
|
||||||
var STOP = 3;
|
var STOP = 3;
|
||||||
var SHOW = 4;
|
var SHOW = 4;
|
||||||
var HIDE = 5;
|
var HIDE = 5;
|
||||||
|
var LOAD = 6;
|
||||||
|
|
||||||
var COLORS = [];
|
var COLORS = [];
|
||||||
COLORS[PLAY] = { red: PLAY, green: 0, blue: 0 };
|
COLORS[PLAY] = { red: PLAY, green: 0, blue: 0 };
|
||||||
|
@ -46,10 +44,11 @@ COLORS[PLAY_LOOP] = { red: PLAY_LOOP, green: 0, blue: 0 };
|
||||||
COLORS[STOP] = { red: STOP, green: 0, blue: 0 };
|
COLORS[STOP] = { red: STOP, green: 0, blue: 0 };
|
||||||
COLORS[SHOW] = { red: SHOW, green: 0, blue: 0 };
|
COLORS[SHOW] = { red: SHOW, green: 0, blue: 0 };
|
||||||
COLORS[HIDE] = { red: HIDE, green: 0, blue: 0 };
|
COLORS[HIDE] = { red: HIDE, green: 0, blue: 0 };
|
||||||
|
COLORS[LOAD] = { red: LOAD, green: 0, blue: 0 };
|
||||||
|
|
||||||
controlEntityPosition.x += id * controlEntitySize;
|
controlEntityPosition.x += id * controlEntitySize;
|
||||||
|
|
||||||
Avatar.loadRecording(filename);
|
Avatar.loadRecording(clip_url);
|
||||||
|
|
||||||
Avatar.setPlayFromCurrentLocation(playFromCurrentLocation);
|
Avatar.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||||
Avatar.setPlayerUseDisplayName(useDisplayName);
|
Avatar.setPlayerUseDisplayName(useDisplayName);
|
||||||
|
@ -68,7 +67,9 @@ function setupEntityViewer() {
|
||||||
EntityViewer.queryOctree();
|
EntityViewer.queryOctree();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAction(controlEntity) {
|
function getAction(controlEntity) {
|
||||||
|
clip_url = controlEntity.userData;
|
||||||
|
|
||||||
if (controlEntity === null ||
|
if (controlEntity === null ||
|
||||||
controlEntity.position.x !== controlEntityPosition.x ||
|
controlEntity.position.x !== controlEntityPosition.x ||
|
||||||
controlEntity.position.y !== controlEntityPosition.y ||
|
controlEntity.position.y !== controlEntityPosition.y ||
|
||||||
|
@ -141,6 +142,12 @@ function update(event) {
|
||||||
}
|
}
|
||||||
Agent.isAvatar = false;
|
Agent.isAvatar = false;
|
||||||
break;
|
break;
|
||||||
|
case LOAD:
|
||||||
|
print("Load");
|
||||||
|
if(clip_url !== null) {
|
||||||
|
Avatar.loadRecording(clip_url);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case DO_NOTHING:
|
case DO_NOTHING:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
73
examples/example/avatarcontrol/handControlledHead.js
Normal file
73
examples/example/avatarcontrol/handControlledHead.js
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
//
|
||||||
|
// handControlledHead.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Alessandro Signa on 10/11/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This script allows you to look around, driving the rotation of the avatar's head by the right hand orientation.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
const YAW_MULTIPLIER = 20000;
|
||||||
|
const PITCH_MULTIPLIER = 15000;
|
||||||
|
const EPSILON = 0.001;
|
||||||
|
var firstPress = true;
|
||||||
|
var handPreviousVerticalRotation = 0.0;
|
||||||
|
var handCurrentVerticalRotation = 0.0;
|
||||||
|
var handPreviousHorizontalRotation = 0.0;
|
||||||
|
var handCurrentHorizontalRotation = 0.0;
|
||||||
|
var rotatedHandPosition;
|
||||||
|
var rotatedTipPosition;
|
||||||
|
|
||||||
|
function update(deltaTime) {
|
||||||
|
if(Controller.getValue(Controller.Standard.RightPrimaryThumb)){
|
||||||
|
pitchManager(deltaTime);
|
||||||
|
}else if(!firstPress){
|
||||||
|
firstPress = true;
|
||||||
|
}
|
||||||
|
if(firstPress && MyAvatar.headYaw){
|
||||||
|
MyAvatar.headYaw -= MyAvatar.headYaw/10;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function pitchManager(deltaTime){
|
||||||
|
|
||||||
|
rotatedHandPosition = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, -MyAvatar.bodyYaw, 0), MyAvatar.getRightHandPosition());
|
||||||
|
rotatedTipPosition = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, -MyAvatar.bodyYaw, 0), MyAvatar.getRightHandTipPosition());
|
||||||
|
|
||||||
|
handCurrentVerticalRotation = Vec3.subtract(rotatedTipPosition, rotatedHandPosition).y;
|
||||||
|
handCurrentHorizontalRotation = Vec3.subtract(rotatedTipPosition, rotatedHandPosition).x;
|
||||||
|
|
||||||
|
var handCurrentHorizontalRotationFiltered = handCurrentHorizontalRotation;
|
||||||
|
|
||||||
|
//to avoid yaw drift
|
||||||
|
if((handCurrentHorizontalRotation - handPreviousHorizontalRotation) < EPSILON && (handCurrentHorizontalRotation - handPreviousHorizontalRotation) > -EPSILON){
|
||||||
|
handCurrentHorizontalRotationFiltered = handPreviousHorizontalRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(firstPress){
|
||||||
|
handPreviousVerticalRotation = handCurrentVerticalRotation;
|
||||||
|
handPreviousHorizontalRotation = handCurrentHorizontalRotation;
|
||||||
|
firstPress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyAvatar.headPitch += (handCurrentVerticalRotation - handPreviousVerticalRotation)*PITCH_MULTIPLIER*deltaTime;
|
||||||
|
MyAvatar.headYaw -= (handCurrentHorizontalRotationFiltered - handPreviousHorizontalRotation)*YAW_MULTIPLIER*deltaTime;
|
||||||
|
|
||||||
|
|
||||||
|
handPreviousVerticalRotation = handCurrentVerticalRotation;
|
||||||
|
handPreviousHorizontalRotation = handCurrentHorizontalRotationFiltered;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean(){
|
||||||
|
MyAvatar.headYaw = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Script.update.connect(update);
|
||||||
|
Script.scriptEnding.connect(clean);
|
265
examples/example/games/color_busters/colorBusterWand.js
Normal file
265
examples/example/games/color_busters/colorBusterWand.js
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
//
|
||||||
|
// colorBusterWand.js
|
||||||
|
//
|
||||||
|
// Created by James B. Pollack @imgntn on 11/2/2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This is the entity script that attaches to a wand for the Color Busters game
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
Script.include("../../../libraries/utils.js");
|
||||||
|
|
||||||
|
var COMBINED_COLOR_DURATION = 5;
|
||||||
|
|
||||||
|
var INDICATOR_OFFSET_UP = 0.40;
|
||||||
|
|
||||||
|
var REMOVE_CUBE_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/color_busters/boop.wav';
|
||||||
|
var COMBINE_COLORS_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/color_busters/powerup.wav';
|
||||||
|
|
||||||
|
var COLOR_INDICATOR_DIMENSIONS = {
|
||||||
|
x: 0.10,
|
||||||
|
y: 0.10,
|
||||||
|
z: 0.10
|
||||||
|
};
|
||||||
|
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
function ColorBusterWand() {
|
||||||
|
_this = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorBusterWand.prototype = {
|
||||||
|
combinedColorsTimer: null,
|
||||||
|
soundIsPlaying: false,
|
||||||
|
preload: function(entityID) {
|
||||||
|
print("preload");
|
||||||
|
this.entityID = entityID;
|
||||||
|
this.REMOVE_CUBE_SOUND = SoundCache.getSound(REMOVE_CUBE_SOUND_URL);
|
||||||
|
this.COMBINE_COLORS_SOUND = SoundCache.getSound(COMBINE_COLORS_SOUND_URL);
|
||||||
|
},
|
||||||
|
|
||||||
|
collisionWithEntity: function(me, otherEntity, collision) {
|
||||||
|
var otherProperties = Entities.getEntityProperties(otherEntity, ["name", "userData"]);
|
||||||
|
var myProperties = Entities.getEntityProperties(me, ["userData"]);
|
||||||
|
var myUserData = JSON.parse(myProperties.userData);
|
||||||
|
var otherUserData = JSON.parse(otherProperties.userData);
|
||||||
|
|
||||||
|
if (otherProperties.name === 'Hifi-ColorBusterWand') {
|
||||||
|
print('HIT ANOTHER COLOR WAND!!');
|
||||||
|
if (otherUserData.hifiColorBusterWandKey.colorLocked !== true && myUserData.hifiColorBusterWandKey.colorLocked !== true) {
|
||||||
|
if (otherUserData.hifiColorBusterWandKey.originalColorName === myUserData.hifiColorBusterWandKey.originalColorName) {
|
||||||
|
print('BUT ITS THE SAME COLOR!')
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
print('COMBINE COLORS!' + this.entityID);
|
||||||
|
this.combineColorsWithOtherWand(otherUserData.hifiColorBusterWandKey.originalColorName, myUserData.hifiColorBusterWandKey.originalColorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherProperties.name === 'Hifi-ColorBusterCube') {
|
||||||
|
if (otherUserData.hifiColorBusterCubeKey.originalColorName === myUserData.hifiColorBusterWandKey.currentColor) {
|
||||||
|
print('HIT THE SAME COLOR CUBE');
|
||||||
|
this.removeCubeOfSameColor(otherEntity);
|
||||||
|
} else {
|
||||||
|
print('HIT A CUBE OF A DIFFERENT COLOR');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
combineColorsWithOtherWand: function(otherColor, myColor) {
|
||||||
|
print('combining my :' + myColor + " with their: " + otherColor);
|
||||||
|
|
||||||
|
if ((myColor === 'violet') || (myColor === 'orange') || (myColor === 'green')) {
|
||||||
|
print('MY WAND ALREADY COMBINED');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newColor;
|
||||||
|
if ((otherColor === 'red' && myColor == 'yellow') || (myColor === 'red' && otherColor === 'yellow')) {
|
||||||
|
//orange
|
||||||
|
newColor = 'orange';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((otherColor === 'red' && myColor == 'blue') || (myColor === 'red' && otherColor === 'blue')) {
|
||||||
|
//violet
|
||||||
|
newColor = 'violet';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((otherColor === 'blue' && myColor == 'yellow') || (myColor === 'blue' && otherColor === 'yellow')) {
|
||||||
|
//green.
|
||||||
|
newColor = 'green';
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.combinedColorsTimer = Script.setTimeout(function() {
|
||||||
|
_this.resetToOriginalColor(myColor);
|
||||||
|
_this.combinedColorsTimer = null;
|
||||||
|
}, COMBINED_COLOR_DURATION * 1000);
|
||||||
|
|
||||||
|
setEntityCustomData('hifiColorBusterWandKey', this.entityID, {
|
||||||
|
owner: MyAvatar.sessionUUID,
|
||||||
|
currentColor: newColor,
|
||||||
|
originalColorName: myColor,
|
||||||
|
colorLocked: false
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.playSoundAtCurrentPosition(false);
|
||||||
|
},
|
||||||
|
|
||||||
|
setCurrentColor: function(newColor) {
|
||||||
|
var color;
|
||||||
|
|
||||||
|
if (newColor === 'orange') {
|
||||||
|
color = {
|
||||||
|
red: 255,
|
||||||
|
green: 165,
|
||||||
|
blue: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newColor === 'violet') {
|
||||||
|
color = {
|
||||||
|
red: 128,
|
||||||
|
green: 0,
|
||||||
|
blue: 128
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newColor === 'green') {
|
||||||
|
color = {
|
||||||
|
red: 0,
|
||||||
|
green: 255,
|
||||||
|
blue: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newColor === 'red') {
|
||||||
|
color = {
|
||||||
|
red: 255,
|
||||||
|
green: 0,
|
||||||
|
blue: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newColor === 'yellow') {
|
||||||
|
color = {
|
||||||
|
red: 255,
|
||||||
|
green: 255,
|
||||||
|
blue: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newColor === 'blue') {
|
||||||
|
color = {
|
||||||
|
red: 0,
|
||||||
|
green: 0,
|
||||||
|
blue: 255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Entities.editEntity(this.colorIndicator, {
|
||||||
|
color: color
|
||||||
|
});
|
||||||
|
|
||||||
|
// print('SET THIS COLOR INDICATOR TO:' + newColor);
|
||||||
|
},
|
||||||
|
|
||||||
|
resetToOriginalColor: function(myColor) {
|
||||||
|
setEntityCustomData('hifiColorBusterWandKey', this.entityID, {
|
||||||
|
owner: MyAvatar.sessionUUID,
|
||||||
|
currentColor: myColor,
|
||||||
|
originalColorName: myColor,
|
||||||
|
colorLocked: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setCurrentColor(myColor);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeCubeOfSameColor: function(cube) {
|
||||||
|
this.playSoundAtCurrentPosition(true);
|
||||||
|
Entities.callEntityMethod(cube, 'cubeEnding');
|
||||||
|
Entities.deleteEntity(cube);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
startNearGrab: function() {
|
||||||
|
this.currentProperties = Entities.getEntityProperties(this.entityID);
|
||||||
|
this.createColorIndicator();
|
||||||
|
},
|
||||||
|
|
||||||
|
continueNearGrab: function() {
|
||||||
|
this.currentProperties = Entities.getEntityProperties(this.entityID);
|
||||||
|
|
||||||
|
var color = JSON.parse(this.currentProperties.userData).hifiColorBusterWandKey.currentColor;
|
||||||
|
|
||||||
|
this.setCurrentColor(color);
|
||||||
|
this.updateColorIndicatorLocation();
|
||||||
|
},
|
||||||
|
|
||||||
|
releaseGrab: function() {
|
||||||
|
Entities.deleteEntity(this.colorIndicator);
|
||||||
|
if (this.combinedColorsTimer !== null) {
|
||||||
|
Script.clearTimeout(this.combinedColorsTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
createColorIndicator: function(color) {
|
||||||
|
|
||||||
|
|
||||||
|
var properties = {
|
||||||
|
name: 'Hifi-ColorBusterIndicator',
|
||||||
|
type: 'Box',
|
||||||
|
dimensions: COLOR_INDICATOR_DIMENSIONS,
|
||||||
|
position: this.currentProperties.position,
|
||||||
|
collisionsWillMove: false,
|
||||||
|
ignoreForCollisions: true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.colorIndicator = Entities.addEntity(properties);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateColorIndicatorLocation: function() {
|
||||||
|
|
||||||
|
var position;
|
||||||
|
|
||||||
|
var upVector = Quat.getUp(this.currentProperties.rotation);
|
||||||
|
var indicatorVector = Vec3.multiply(upVector, INDICATOR_OFFSET_UP);
|
||||||
|
position = Vec3.sum(this.currentProperties.position, indicatorVector);
|
||||||
|
|
||||||
|
var properties = {
|
||||||
|
position: position,
|
||||||
|
rotation: this.currentProperties.rotation
|
||||||
|
}
|
||||||
|
|
||||||
|
Entities.editEntity(this.colorIndicator, properties);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
playSoundAtCurrentPosition: function(isRemoveCubeSound) {
|
||||||
|
|
||||||
|
var position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||||
|
var audioProperties = {
|
||||||
|
volume: 0.25,
|
||||||
|
position: position
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isRemoveCubeSound === true) {
|
||||||
|
Audio.playSound(this.REMOVE_CUBE_SOUND, audioProperties);
|
||||||
|
} else {
|
||||||
|
Audio.playSound(this.COMBINE_COLORS_SOUND, audioProperties);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return new ColorBusterWand();
|
||||||
|
});
|
130
examples/example/games/color_busters/createColorBusterCubes.js
Normal file
130
examples/example/games/color_busters/createColorBusterCubes.js
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
//
|
||||||
|
// createColorBusterCubes.js
|
||||||
|
//
|
||||||
|
// Created by James B. Pollack @imgntn on 11/2/2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This script creates cubes that can be removed with a Color Buster wand.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
var DELETE_AT_ENDING = false;
|
||||||
|
|
||||||
|
var CUBE_DIMENSIONS = {
|
||||||
|
x: 1,
|
||||||
|
y: 1,
|
||||||
|
z: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
var NUMBER_OF_CUBES_PER_SIDE = 8;
|
||||||
|
|
||||||
|
var STARTING_CORNER_POSITION = {
|
||||||
|
x: 100,
|
||||||
|
y: 100,
|
||||||
|
z: 100
|
||||||
|
};
|
||||||
|
var STARTING_COLORS = [
|
||||||
|
['red', {
|
||||||
|
red: 255,
|
||||||
|
green: 0,
|
||||||
|
blue: 0
|
||||||
|
}],
|
||||||
|
['yellow', {
|
||||||
|
red: 255,
|
||||||
|
green: 255,
|
||||||
|
blue: 0
|
||||||
|
}],
|
||||||
|
['blue', {
|
||||||
|
red: 0,
|
||||||
|
green: 0,
|
||||||
|
blue: 255
|
||||||
|
}],
|
||||||
|
['orange', {
|
||||||
|
red: 255,
|
||||||
|
green: 165,
|
||||||
|
blue: 0
|
||||||
|
}],
|
||||||
|
['violet', {
|
||||||
|
red: 128,
|
||||||
|
green: 0,
|
||||||
|
blue: 128
|
||||||
|
}],
|
||||||
|
['green', {
|
||||||
|
red: 0,
|
||||||
|
green: 255,
|
||||||
|
blue: 0
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
|
||||||
|
function chooseStartingColor() {
|
||||||
|
var startingColor = STARTING_COLORS[Math.floor(Math.random() * STARTING_COLORS.length)];
|
||||||
|
return startingColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cubes = [];
|
||||||
|
|
||||||
|
function createColorBusterCube(row, column, vertical) {
|
||||||
|
|
||||||
|
print('make cube at ' + row + ':' + column + ":" + vertical);
|
||||||
|
|
||||||
|
var position = {
|
||||||
|
x: STARTING_CORNER_POSITION.x + row,
|
||||||
|
y: STARTING_CORNER_POSITION.y + vertical,
|
||||||
|
z: STARTING_CORNER_POSITION.z + column
|
||||||
|
};
|
||||||
|
|
||||||
|
var startingColor = chooseStartingColor();
|
||||||
|
var colorBusterCubeProperties = {
|
||||||
|
name: 'Hifi-ColorBusterCube',
|
||||||
|
type: 'Box',
|
||||||
|
dimensions: CUBE_DIMENSIONS,
|
||||||
|
collisionsWillMove: false,
|
||||||
|
ignoreForCollisions: false,
|
||||||
|
color: startingColor[1],
|
||||||
|
position: position,
|
||||||
|
userData: JSON.stringify({
|
||||||
|
hifiColorBusterCubeKey: {
|
||||||
|
originalColorName: startingColor[0]
|
||||||
|
},
|
||||||
|
grabbableKey: {
|
||||||
|
grabbable: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
var cube = Entities.addEntity(colorBusterCubeProperties);
|
||||||
|
cubes.push(cube);
|
||||||
|
return cube
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBoard() {
|
||||||
|
var vertical;
|
||||||
|
var row;
|
||||||
|
var column;
|
||||||
|
for (vertical = 0; vertical < NUMBER_OF_CUBES_PER_SIDE; vertical++) {
|
||||||
|
print('vertical:' + vertical)
|
||||||
|
//create a single layer
|
||||||
|
for (row = 0; row < NUMBER_OF_CUBES_PER_SIDE; row++) {
|
||||||
|
print('row:' + row)
|
||||||
|
for (column = 0; column < NUMBER_OF_CUBES_PER_SIDE; column++) {
|
||||||
|
print('column:' + column)
|
||||||
|
createColorBusterCube(row, column, vertical)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteCubes() {
|
||||||
|
while (cubes.length > 0) {
|
||||||
|
Entities.deleteEntity(cubes.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DELETE_AT_ENDING === true) {
|
||||||
|
Script.scriptEnding.connect(deleteCubes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
createBoard();
|
|
@ -0,0 +1,99 @@
|
||||||
|
//
|
||||||
|
// createColorBusterWand.js
|
||||||
|
//
|
||||||
|
// Created by James B. Pollack @imgntn on 11/2/2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This script creates a wand that can be used to remove color buster blocks. Touch your wand to someone else's to combine colors.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var DELETE_AT_ENDING = false;
|
||||||
|
|
||||||
|
var COLOR_WAND_MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/color_busters/wand.fbx';
|
||||||
|
var COLOR_WAND_COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/color_busters/wand_collision_hull.obj';
|
||||||
|
var COLOR_WAND_SCRIPT_URL = Script.resolvePath('colorBusterWand.js');
|
||||||
|
|
||||||
|
var COLOR_WAND_DIMENSIONS = {
|
||||||
|
x: 0.04,
|
||||||
|
y: 0.87,
|
||||||
|
z: 0.04
|
||||||
|
};
|
||||||
|
|
||||||
|
var COLOR_WAND_START_POSITION = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
var STARTING_COLORS = [
|
||||||
|
['red', {
|
||||||
|
red: 255,
|
||||||
|
green: 0,
|
||||||
|
blue: 0
|
||||||
|
}],
|
||||||
|
['yellow', {
|
||||||
|
red: 255,
|
||||||
|
green: 255,
|
||||||
|
blue: 0
|
||||||
|
}],
|
||||||
|
['blue', {
|
||||||
|
red: 0,
|
||||||
|
green: 0,
|
||||||
|
blue: 255
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
|
||||||
|
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {
|
||||||
|
x: 0,
|
||||||
|
y: 0.5,
|
||||||
|
z: 0
|
||||||
|
}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
|
|
||||||
|
function chooseStartingColor() {
|
||||||
|
var startingColor = STARTING_COLORS[Math.floor(Math.random() * STARTING_COLORS.length)];
|
||||||
|
return startingColor
|
||||||
|
}
|
||||||
|
|
||||||
|
var wand;
|
||||||
|
|
||||||
|
function createColorBusterWand() {
|
||||||
|
var startingColor = chooseStartingColor();
|
||||||
|
var colorBusterWandProperties = {
|
||||||
|
name: 'Hifi-ColorBusterWand',
|
||||||
|
type: 'Model',
|
||||||
|
modelURL: COLOR_WAND_MODEL_URL,
|
||||||
|
shapeType: 'compound',
|
||||||
|
compoundShapeURL: COLOR_WAND_COLLISION_HULL_URL,
|
||||||
|
dimensions: COLOR_WAND_DIMENSIONS,
|
||||||
|
position: center,
|
||||||
|
script: COLOR_WAND_SCRIPT_URL,
|
||||||
|
collisionsWillMove: true,
|
||||||
|
userData: JSON.stringify({
|
||||||
|
hifiColorBusterWandKey: {
|
||||||
|
owner: MyAvatar.sessionUUID,
|
||||||
|
currentColor: startingColor[0],
|
||||||
|
originalColorName: startingColor[0],
|
||||||
|
colorLocked: false
|
||||||
|
},
|
||||||
|
grabbableKey: {
|
||||||
|
invertSolidWhileHeld: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
wand = Entities.addEntity(colorBusterWandProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteWand() {
|
||||||
|
Entities.deleteEntity(wand);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DELETE_AT_ENDING === true) {
|
||||||
|
Script.scriptEnding.connect(deleteWand);
|
||||||
|
}
|
||||||
|
|
||||||
|
createColorBusterWand();
|
|
@ -25,6 +25,7 @@
|
||||||
#include "RecurseOctreeToMapOperator.h"
|
#include "RecurseOctreeToMapOperator.h"
|
||||||
#include "LogHandler.h"
|
#include "LogHandler.h"
|
||||||
|
|
||||||
|
static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50;
|
||||||
|
|
||||||
EntityTree::EntityTree(bool shouldReaverage) :
|
EntityTree::EntityTree(bool shouldReaverage) :
|
||||||
Octree(shouldReaverage),
|
Octree(shouldReaverage),
|
||||||
|
@ -388,16 +389,15 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool i
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) {
|
void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) {
|
||||||
|
quint64 deletedAt = usecTimestampNow();
|
||||||
const RemovedEntities& entities = theOperator.getEntities();
|
const RemovedEntities& entities = theOperator.getEntities();
|
||||||
foreach(const EntityToDeleteDetails& details, entities) {
|
foreach(const EntityToDeleteDetails& details, entities) {
|
||||||
EntityItemPointer theEntity = details.entity;
|
EntityItemPointer theEntity = details.entity;
|
||||||
|
|
||||||
if (getIsServer()) {
|
if (getIsServer()) {
|
||||||
// set up the deleted entities ID
|
// set up the deleted entities ID
|
||||||
quint64 deletedAt = usecTimestampNow();
|
QWriteLocker locker(&_recentlyDeletedEntitiesLock);
|
||||||
_recentlyDeletedEntitiesLock.lockForWrite();
|
|
||||||
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID());
|
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID());
|
||||||
_recentlyDeletedEntitiesLock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
|
@ -888,25 +888,37 @@ void EntityTree::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) {
|
bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) {
|
||||||
|
quint64 considerEntitiesSince = sinceTime - DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER;
|
||||||
|
|
||||||
// we can probably leverage the ordered nature of QMultiMap to do this quickly...
|
// we can probably leverage the ordered nature of QMultiMap to do this quickly...
|
||||||
bool hasSomethingNewer = false;
|
bool hasSomethingNewer = false;
|
||||||
|
|
||||||
_recentlyDeletedEntitiesLock.lockForRead();
|
QReadLocker locker(&_recentlyDeletedEntitiesLock);
|
||||||
QMultiMap<quint64, QUuid>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
QMultiMap<quint64, QUuid>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
||||||
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||||
if (iterator.key() > sinceTime) {
|
if (iterator.key() > considerEntitiesSince) {
|
||||||
hasSomethingNewer = true;
|
hasSomethingNewer = true;
|
||||||
|
break; // if we have at least one item, we don't need to keep searching
|
||||||
}
|
}
|
||||||
++iterator;
|
++iterator;
|
||||||
}
|
}
|
||||||
_recentlyDeletedEntitiesLock.unlock();
|
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
if (hasSomethingNewer) {
|
||||||
|
int elapsed = usecTimestampNow() - considerEntitiesSince;
|
||||||
|
int difference = considerEntitiesSince - sinceTime;
|
||||||
|
qDebug() << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime
|
||||||
|
<< "considerEntitiesSince:" << considerEntitiesSince << "elapsed:" << elapsed << "difference:" << difference;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return hasSomethingNewer;
|
return hasSomethingNewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sinceTime is an in/out parameter - it will be side effected with the last time sent out
|
// sinceTime is an in/out parameter - it will be side effected with the last time sent out
|
||||||
std::unique_ptr<NLPacket> EntityTree::encodeEntitiesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime,
|
std::unique_ptr<NLPacket> EntityTree::encodeEntitiesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime,
|
||||||
bool& hasMore) {
|
bool& hasMore) {
|
||||||
|
quint64 considerEntitiesSince = sinceTime - DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER;
|
||||||
auto deletesPacket = NLPacket::create(PacketType::EntityErase);
|
auto deletesPacket = NLPacket::create(PacketType::EntityErase);
|
||||||
|
|
||||||
// pack in flags
|
// pack in flags
|
||||||
|
@ -927,48 +939,56 @@ std::unique_ptr<NLPacket> EntityTree::encodeEntitiesDeletedSince(OCTREE_PACKET_S
|
||||||
|
|
||||||
// we keep a multi map of entity IDs to timestamps, we only want to include the entity IDs that have been
|
// we keep a multi map of entity IDs to timestamps, we only want to include the entity IDs that have been
|
||||||
// deleted since we last sent to this node
|
// deleted since we last sent to this node
|
||||||
_recentlyDeletedEntitiesLock.lockForRead();
|
{
|
||||||
|
QReadLocker locker(&_recentlyDeletedEntitiesLock);
|
||||||
|
|
||||||
bool hasFilledPacket = false;
|
bool hasFilledPacket = false;
|
||||||
|
|
||||||
auto it = _recentlyDeletedEntityItemIDs.constBegin();
|
auto it = _recentlyDeletedEntityItemIDs.constBegin();
|
||||||
while (it != _recentlyDeletedEntityItemIDs.constEnd()) {
|
while (it != _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||||
QList<QUuid> values = _recentlyDeletedEntityItemIDs.values(it.key());
|
QList<QUuid> values = _recentlyDeletedEntityItemIDs.values(it.key());
|
||||||
for (int valueItem = 0; valueItem < values.size(); ++valueItem) {
|
for (int valueItem = 0; valueItem < values.size(); ++valueItem) {
|
||||||
|
|
||||||
// if the timestamp is more recent then out last sent time, include it
|
// if the timestamp is more recent then out last sent time, include it
|
||||||
if (it.key() > sinceTime) {
|
if (it.key() > considerEntitiesSince) {
|
||||||
QUuid entityID = values.at(valueItem);
|
QUuid entityID = values.at(valueItem);
|
||||||
deletesPacket->write(entityID.toRfc4122());
|
|
||||||
|
|
||||||
++numberOfIDs;
|
// FIXME - we still seem to see cases where incorrect EntityIDs get sent from the server
|
||||||
|
// to the client. These were causing "lost" entities like flashlights and laser pointers
|
||||||
|
// now that we keep around some additional history of the erased entities and resend that
|
||||||
|
// history for a longer time window, these entities are not "lost". But we haven't yet
|
||||||
|
// found/fixed the underlying issue that caused bad UUIDs to be sent to some users.
|
||||||
|
deletesPacket->write(entityID.toRfc4122());
|
||||||
|
++numberOfIDs;
|
||||||
|
|
||||||
// check to make sure we have room for one more ID
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
if (NUM_BYTES_RFC4122_UUID > deletesPacket->bytesAvailableForWrite()) {
|
qDebug() << "EntityTree::encodeEntitiesDeletedSince() including:" << entityID;
|
||||||
hasFilledPacket = true;
|
#endif
|
||||||
break;
|
|
||||||
|
// check to make sure we have room for one more ID
|
||||||
|
if (NUM_BYTES_RFC4122_UUID > deletesPacket->bytesAvailableForWrite()) {
|
||||||
|
hasFilledPacket = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check to see if we're about to return
|
||||||
|
if (hasFilledPacket) {
|
||||||
|
// let our caller know how far we got
|
||||||
|
sinceTime = it.key();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if we're about to return
|
// if we got to the end, then we're done sending
|
||||||
if (hasFilledPacket) {
|
if (it == _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||||
// let our caller know how far we got
|
hasMore = false;
|
||||||
sinceTime = it.key();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we got to the end, then we're done sending
|
|
||||||
if (it == _recentlyDeletedEntityItemIDs.constEnd()) {
|
|
||||||
hasMore = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_recentlyDeletedEntitiesLock.unlock();
|
|
||||||
|
|
||||||
// replace the count for the number of included IDs
|
// replace the count for the number of included IDs
|
||||||
deletesPacket->seek(numberOfIDsPos);
|
deletesPacket->seek(numberOfIDsPos);
|
||||||
deletesPacket->writePrimitive(numberOfIDs);
|
deletesPacket->writePrimitive(numberOfIDs);
|
||||||
|
@ -979,14 +999,14 @@ std::unique_ptr<NLPacket> EntityTree::encodeEntitiesDeletedSince(OCTREE_PACKET_S
|
||||||
|
|
||||||
// called by the server when it knows all nodes have been sent deleted packets
|
// called by the server when it knows all nodes have been sent deleted packets
|
||||||
void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
|
void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
|
||||||
|
quint64 considerSinceTime = sinceTime - DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER;
|
||||||
QSet<quint64> keysToRemove;
|
QSet<quint64> keysToRemove;
|
||||||
|
QWriteLocker locker(&_recentlyDeletedEntitiesLock);
|
||||||
_recentlyDeletedEntitiesLock.lockForWrite();
|
|
||||||
QMultiMap<quint64, QUuid>::iterator iterator = _recentlyDeletedEntityItemIDs.begin();
|
QMultiMap<quint64, QUuid>::iterator iterator = _recentlyDeletedEntityItemIDs.begin();
|
||||||
|
|
||||||
// First find all the keys in the map that are older and need to be deleted
|
// First find all the keys in the map that are older and need to be deleted
|
||||||
while (iterator != _recentlyDeletedEntityItemIDs.end()) {
|
while (iterator != _recentlyDeletedEntityItemIDs.end()) {
|
||||||
if (iterator.key() <= sinceTime) {
|
if (iterator.key() <= considerSinceTime) {
|
||||||
keysToRemove << iterator.key();
|
keysToRemove << iterator.key();
|
||||||
}
|
}
|
||||||
++iterator;
|
++iterator;
|
||||||
|
@ -996,13 +1016,14 @@ void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
|
||||||
foreach (quint64 value, keysToRemove) {
|
foreach (quint64 value, keysToRemove) {
|
||||||
_recentlyDeletedEntityItemIDs.remove(value);
|
_recentlyDeletedEntityItemIDs.remove(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_recentlyDeletedEntitiesLock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
|
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
|
||||||
int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) {
|
int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) {
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
qDebug() << "EntityTree::processEraseMessage()";
|
||||||
|
#endif
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
packet.seek(sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME));
|
packet.seek(sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME));
|
||||||
|
|
||||||
|
@ -1020,6 +1041,9 @@ int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& s
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid entityID = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
QUuid entityID = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
qDebug() << " ---- EntityTree::processEraseMessage() contained ID:" << entityID;
|
||||||
|
#endif
|
||||||
|
|
||||||
EntityItemID entityItemID(entityID);
|
EntityItemID entityItemID(entityID);
|
||||||
entityItemIDsToDelete << entityItemID;
|
entityItemIDsToDelete << entityItemID;
|
||||||
|
@ -1039,6 +1063,9 @@ int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& s
|
||||||
// NOTE: Caller must lock the tree before calling this.
|
// NOTE: Caller must lock the tree before calling this.
|
||||||
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
|
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
|
||||||
int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
qDebug() << "EntityTree::processEraseMessageDetails()";
|
||||||
|
#endif
|
||||||
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
|
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
|
||||||
const unsigned char* dataAt = packetData;
|
const unsigned char* dataAt = packetData;
|
||||||
size_t packetLength = dataByteArray.size();
|
size_t packetLength = dataByteArray.size();
|
||||||
|
@ -1065,6 +1092,10 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons
|
||||||
dataAt += encodedID.size();
|
dataAt += encodedID.size();
|
||||||
processedBytes += encodedID.size();
|
processedBytes += encodedID.size();
|
||||||
|
|
||||||
|
#ifdef EXTRA_ERASE_DEBUGGING
|
||||||
|
qDebug() << " ---- EntityTree::processEraseMessageDetails() contains id:" << entityID;
|
||||||
|
#endif
|
||||||
|
|
||||||
EntityItemID entityItemID(entityID);
|
EntityItemID entityItemID(entityID);
|
||||||
entityItemIDsToDelete << entityItemID;
|
entityItemIDsToDelete << entityItemID;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue