Merge pull request #4920 from sethalves/no-id-swap-redux

No id swap redux
This commit is contained in:
Brad Hefta-Gaub 2015-05-21 09:51:11 -07:00
commit a503deb3ca
53 changed files with 237 additions and 872 deletions

View file

@ -73,17 +73,6 @@ void Agent::readPendingDatagrams() {
}
}
} else if (datagramPacketType == PacketTypeEntityAddResponse) {
// this will keep creatorTokenIDs to IDs mapped correctly
EntityItemID::handleAddEntityResponse(receivedPacket);
// also give our local entity tree a chance to remap any internal locally created entities
_entityViewer.getTree()->handleAddEntityResponse(receivedPacket);
// Make sure our Node and NodeList knows we've heard from this node.
SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
} else if (datagramPacketType == PacketTypeOctreeStats
|| datagramPacketType == PacketTypeEntityData
|| datagramPacketType == PacketTypeEntityErase

View file

@ -60,30 +60,6 @@ void EntityServer::beforeRun() {
}
void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) {
unsigned char outputBuffer[MAX_PACKET_SIZE];
unsigned char* copyAt = outputBuffer;
auto nodeList = DependencyManager::get<NodeList>();
int numBytesPacketHeader = nodeList->populatePacketHeader(reinterpret_cast<char*>(outputBuffer), PacketTypeEntityAddResponse);
int packetLength = numBytesPacketHeader;
copyAt += numBytesPacketHeader;
// encode the creatorTokenID
uint32_t creatorTokenID = newEntity.getCreatorTokenID();
memcpy(copyAt, &creatorTokenID, sizeof(creatorTokenID));
copyAt += sizeof(creatorTokenID);
packetLength += sizeof(creatorTokenID);
// encode the entity ID
QUuid entityID = newEntity.getID();
QByteArray encodedID = entityID.toRfc4122();
memcpy(copyAt, encodedID.constData(), encodedID.size());
copyAt += sizeof(entityID);
packetLength += sizeof(entityID);
nodeList->writeDatagram((char*) outputBuffer, packetLength, senderNode);
}

View file

@ -198,7 +198,7 @@ function checkControllerSide(hand) {
var closestEntity = Entities.findClosestEntity(hand.palmPosition(), CATCH_RADIUS);
var modelUrl = Entities.getEntityProperties(closestEntity).modelURL;
print("lol2"+closestEntity.isKnownID);
if (closestEntity.isKnownID && validFrisbeeURL(Entities.getEntityProperties(closestEntity).modelURL)) {
if (closestEntity && validFrisbeeURL(Entities.getEntityProperties(closestEntity).modelURL)) {
print("lol");
Entities.editEntity(closestEntity, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true});
Entities.deleteEntity(closestEntity);
@ -448,4 +448,4 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Menu.menuItemEvent.connect(menuItemEvent);
Script.scriptEnding.connect(scriptEnding);
Script.update.connect(checkController);
Script.update.connect(controlFrisbees);
Script.update.connect(controlFrisbees);

View file

@ -386,13 +386,6 @@ MyAvatar.attach(gunModel, "LeftHand", {x:-0.04, y: 0.22, z: 0.02}, Quat.fromPitc
Script.setTimeout(playLoadSound, 2000);
function update(deltaTime) {
if (bulletID && !bulletID.isKnownID) {
bulletID = Entities.identifyEntity(bulletID);
}
if (targetID && !targetID.isKnownID) {
targetID = Entities.identifyEntity(targetID);
}
if (activeControllers == 0) {
if (Controller.getNumberOfSpatialControls() > 0) {
activeControllers = Controller.getNumberOfSpatialControls();

View file

@ -132,12 +132,6 @@ function update(deltaTime) {
return;
}
if (!paddle.isKnownID) {
paddle = Entities.identifyEntity(paddle);
}
if (!ball.isKnownID) {
ball = Entities.identifyEntity(ball);
} else {
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
@ -157,7 +151,7 @@ function update(deltaTime) {
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
velocity: Controller.getSpatialControlVelocity(controllerID),
rotation: paddleWorldOrientation });
}
}
function entityCollisionWithEntity(entity1, entity2, collision) {

View file

@ -109,17 +109,10 @@ function checkControllerSide(whichSide) {
var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5));
// If I don't currently have a ball in my hand, then try to catch closest one
if (leftHandEntity && !leftHandEntity.isKnownID) {
leftHandEntity = Entities.identifyEntity(leftHandEntity);
}
if (rightHandEntity && !rightHandEntity.isKnownID) {
rightHandEntity = Entities.identifyEntity(rightHandEntity);
}
if (!ballAlreadyInHand && grabButtonPressed) {
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
if (closestEntity.isKnownID) {
if (closestEntity) {
var foundProperties = Entities.getEntityProperties(closestEntity);
if (Vec3.length(foundProperties.velocity) > 0.0) {

View file

@ -579,16 +579,6 @@ function findClickedEntity(event) {
}
var foundEntity = result.entityID;
if (!foundEntity.isKnownID) {
var identify = Entities.identifyEntity(foundEntity);
if (!identify.isKnownID) {
print("Unknown ID " + identify.id + " (update loop " + foundEntity.id + ")");
return null;
}
foundEntity = identify;
}
return { pickRay: pickRay, entityID: foundEntity };
}
@ -610,7 +600,7 @@ function mousePressEvent(event) {
}
}
var highlightedEntityID = { isKnownID: false };
var highlightedEntityID = null;
var mouseCapturedByTool = false;
var lastMousePosition = null;
var idleMouseTimerId = null;
@ -625,9 +615,6 @@ function mouseMove(event) {
mouseHasMovedSincePress = true;
if (placingEntityID) {
if (!placingEntityID.isKnownID) {
placingEntityID = Entities.identifyEntity(placingEntityID);
}
var pickRay = Camera.computePickRay(event.x, event.y);
var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE;
var offset = Vec3.multiply(distance, pickRay.direction);
@ -664,9 +651,9 @@ function highlightEntityUnderCursor(position, accurateRay) {
var pickRay = Camera.computePickRay(position.x, position.y);
var entityIntersection = Entities.findRayIntersection(pickRay, accurateRay);
if (entityIntersection.accurate) {
if(highlightedEntityID.isKnownID && highlightedEntityID.id != entityIntersection.entityID.id) {
if(highlightedEntityID && highlightedEntityID != entityIntersection.entityID) {
selectionDisplay.unhighlightSelectable(highlightedEntityID);
highlightedEntityID = { id: -1, isKnownID: false };
highlightedEntityID = { id: -1 };
}
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
@ -677,7 +664,7 @@ function highlightEntityUnderCursor(position, accurateRay) {
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (entityIntersection.entityID.isKnownID && sizeOK) {
if (entityIntersection.entityID && sizeOK) {
if (wantEntityGlow) {
Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 });
}
@ -736,7 +723,7 @@ function mouseClickEvent(event) {
} else {
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
@ -967,8 +954,8 @@ function deleteSelectedEntities() {
var savedProperties = [];
for (var i = 0; i < selectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
SelectionManager.savedProperties[entityID.id];
var initialProperties = SelectionManager.savedProperties[entityID];
SelectionManager.savedProperties[entityID];
savedProperties.push({
entityID: entityID,
properties: initialProperties
@ -1127,8 +1114,8 @@ function applyEntityProperties(data) {
var selectedEntityIDs = [];
for (var i = 0; i < properties.length; i++) {
var entityID = properties[i].entityID;
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
entityID = DELETED_ENTITY_MAP[entityID.id];
if (DELETED_ENTITY_MAP[entityID] !== undefined) {
entityID = DELETED_ENTITY_MAP[entityID];
}
Entities.editEntity(entityID, properties[i].properties);
selectedEntityIDs.push(entityID);
@ -1137,15 +1124,15 @@ function applyEntityProperties(data) {
var entityID = data.createEntities[i].entityID;
var properties = data.createEntities[i].properties;
var newEntityID = Entities.addEntity(properties);
DELETED_ENTITY_MAP[entityID.id] = newEntityID;
DELETED_ENTITY_MAP[entityID] = newEntityID;
if (data.selectCreated) {
selectedEntityIDs.push(newEntityID);
}
}
for (var i = 0; i < data.deleteEntities.length; i++) {
var entityID = data.deleteEntities[i].entityID;
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
entityID = DELETED_ENTITY_MAP[entityID.id];
if (DELETED_ENTITY_MAP[entityID] !== undefined) {
entityID = DELETED_ENTITY_MAP[entityID];
}
Entities.deleteEntity(entityID);
}
@ -1170,7 +1157,7 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
};
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
var initialProperties = SelectionManager.savedProperties[entityID];
var currentProperties = Entities.getEntityProperties(entityID);
undoData.setProperties.push({
entityID: entityID,

View file

@ -17,8 +17,8 @@
// All callbacks start by updating the properties
this.updateProperties = function(entityID) {
// Piece ID
if (this.entityID === null || !this.entityID.isKnownID) {
this.entityID = Entities.identifyEntity(entityID);
if (this.entityID === null) {
this.entityID = entityID;
}
// Piece Properties
this.properties = Entities.getEntityProperties(this.entityID);
@ -27,12 +27,7 @@
if (this.boardID === null) {
// Read user data string and update boardID
var userData = JSON.parse(this.properties.userData);
var boardID = Entities.identifyEntity(userData.boardID);
if (boardID.isKnownID) {
this.boardID = boardID;
} else {
return;
}
this.boardID = userData.boardID;
}
// Board User Data
@ -52,13 +47,13 @@
// Updates user data related objects
this.updateUserData = function() {
// Get board's user data
if (this.boardID !== null && this.boardID.isKnownID) {
if (this.boardID !== null) {
this.boardUserData = this.getEntityUserData(this.boardID);
if (!(this.boardUserData &&
this.boardUserData.firstTile &&
this.boardUserData.tileSize)) {
print("Incomplete boardUserData " + this.boardID.id);
print("Incomplete boardUserData " + this.boardID);
} else {
this.FIRST_TILE = this.boardUserData.firstTile;
this.TILE_SIZE = this.boardUserData.tileSize;
@ -137,7 +132,7 @@
for (var i = 0; i < others.length; i++) {
var piece = others[i];
if (piece.id != this.entityID.id) {
if (piece.id != this.entityID) {
var properties = Entities.getEntityProperties(piece);
var isWhite = properties.modelURL.search("White") !== -1;
@ -198,4 +193,4 @@
this.updateProperties(entityID); // All callbacks start by updating the properties
this.release(mouseEvent);
};
})
})

View file

@ -35,8 +35,8 @@
}
// All callbacks start by updating the properties
this.updateProperties = function(entityID) {
if (this.entityID === null || !this.entityID.isKnownID) {
this.entityID = Entities.identifyEntity(entityID);
if (this.entityID === null) {
this.entityID = entityID;
}
this.properties = Entities.getEntityProperties(this.entityID);
};

View file

@ -32,14 +32,14 @@
return JSON.parse(JSON.stringify(object));
}
function didEntityExist(entityID) {
return entityID && entityID.isKnownID;
return entityID;
}
function doesEntityExistNow(entityID) {
return entityID && getTrueID(entityID).isKnownID;
return entityID;
}
function getTrueID(entityID) {
var properties = Entities.getEntityProperties(entityID);
return { id: properties.id, creatorTokenID: properties.creatorTokenID, isKnownID: properties.isKnownID };
return { id: properties.id };
}
function getUserData(entityID) {
var properties = Entities.getEntityProperties(entityID);
@ -225,4 +225,4 @@
this.updateRelativeLightPosition();
}
};
})
})

View file

@ -251,8 +251,8 @@
};
// All callbacks start by updating the properties
this.updateProperties = function(entityID) {
if (this.entityID === null || !this.entityID.isKnownID) {
this.entityID = Entities.identifyEntity(entityID);
if (this.entityID === null) {
this.entityID = entityID;
}
this.properties = Entities.getEntityProperties(this.entityID);
};

View file

@ -15,7 +15,7 @@
var bird;
this.preload = function(entityID) {
print("preload("+entityID.id+")");
print("preload("+entityID+")");
bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
};

View file

@ -22,17 +22,17 @@
}
this.preload = function(entityID) {
print("preload("+entityID.id+")");
print("preload("+entityID+")");
bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
};
this.enterEntity = function(entityID) {
print("enterEntity("+entityID.id+")");
print("enterEntity("+entityID+")");
playSound();
};
this.leaveEntity = function(entityID) {
print("leaveEntity("+entityID.id+")");
print("leaveEntity("+entityID+")");
playSound();
};
})

View file

@ -312,7 +312,7 @@
this.indicator[i].position,
this.indicator[i].scale / 2)) {
clickedOnSeat = true;
seat.model = this.entityID; // ??
seat.model = this.entityID;
seat.position = this.indicator[i].position;
seat.rotation = this.indicator[i].orientation;
}
@ -333,8 +333,8 @@
// All callbacks start by updating the properties
this.updateProperties = function(entityID) {
if (this.entityID === null || !this.entityID.isKnownID) {
this.entityID = Entities.identifyEntity(entityID);
if (this.entityID === null) {
this.entityID = entityID;
}
this.properties = Entities.getEntityProperties(this.entityID);
};
@ -369,4 +369,4 @@
this.updateProperties(entityID); // All callbacks start by updating the properties
};
})
})

View file

@ -42,7 +42,6 @@ var originalProperties = {
};
var modelID = Entities.addEntity(originalProperties);
print("Entities.addEntity()... modelID.creatorTokenID = " + modelID.creatorTokenID);
var isPlaying = true;
var playPauseEveryWhile = 360;
@ -98,8 +97,6 @@ function moveModel(deltaTime) {
count++;
//print("modelID.creatorTokenID = " + modelID.creatorTokenID);
if (somethingChanged) {
var newProperties = {
animationIsPlaying: isPlaying,
@ -123,7 +120,7 @@ Script.update.connect(moveModel);
Script.scriptEnding.connect(function () {
print("cleaning up...");
print("modelID="+ modelID.creatorTokenID + ", id:" + modelID.id);
print("modelID=" + modelID);
Models.deleteModel(modelID);
});

View file

@ -106,9 +106,6 @@ function updateButterflies(deltaTime) {
var CHANCE_OF_IMPULSE = 0.04;
for (var i = 0; i < numButterflies; i++) {
if (Math.random() < CHANCE_OF_IMPULSE) {
if (!butterflies[i].isKnownID) {
butterflies[i] = Entities.identifyEntity(butterflies[i]);
}
var properties = Entities.getEntityProperties(butterflies[i]);
if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) {
Entities.editEntity(butterflies[i], { position: flockPosition } );

View file

@ -71,8 +71,6 @@ function moveEntity(deltaTime) {
print("count =" + count);
count++;
print("entityID.creatorTokenID = " + entityID.creatorTokenID);
var newProperties = {
position: {
x: originalProperties.position.x + (count * positionDelta.x),

View file

@ -70,8 +70,6 @@ function moveEntity(deltaTime) {
print("count =" + count);
count++;
print("entityID.creatorTokenID = " + entityID.creatorTokenID);
var newProperties = {
position: {
x: originalProperties.position.x + (count * positionDelta.x),

View file

@ -38,10 +38,6 @@ var moveSearch = { x: 0.1, y: 0, z: 0.1};
var searchRadius = 1;
var searchRadiusChange = 0;
print("entityA.creatorTokenID = " + entityA.creatorTokenID);
print("entityB.creatorTokenID = " + entityB.creatorTokenID);
function scriptEnding() {
print("calling Entities.deleteEntity()");
Entities.deleteEntity(entityA);
@ -77,22 +73,6 @@ function findEntities(deltaTime) {
print("--------------------------");
print("iteration =" + iteration);
iteration++;
// Check to see if we've been notified of the actual identity of the entities we created
if (!entityA.isKnownID) {
var identifyA = Entities.identifyEntity(entityA);
if (identifyA.isKnownID) {
entityA = identifyA;
print(">>>> identified entityA.id = " + entityA.id);
}
}
if (!entityB.isKnownID) {
var identifyB = Entities.identifyEntity(entityB);
if (identifyB.isKnownID) {
entityB = identifyB;
print(">>>> identified entityB.id = " + entityB.id);
}
}
// also check to see if we can "find" entities...
print("searching for entities at:" + searchAt.x + ", " + searchAt.y + ", " + searchAt.z + " radius:" + searchRadius);

View file

@ -177,18 +177,11 @@ function updateBirds(deltaTime) {
var averagePosition = { x: 0, y: 0, z: 0};
var knownBirds = 0;
for(var i =0; i < birdsInFlock; i++) {
// identifyParticle() will check to see that the particle handle we have is in sync with the domain/server
// context. If the handle is for a created particle that now has a known ID it will be updated to be a
// handle with a known ID.
birds[i].particle = Entities.identifyEntity(birds[i].particle);
if (birds[i].particle.isKnownID) {
birds[i].properties = Entities.getEntityProperties(birds[i].particle);
if (birds[i].properties.isKnownID) {
knownBirds++;
averageVelocity = Vec3.sum(averageVelocity, birds[i].properties.velocity);
averagePosition = Vec3.sum(averagePosition, birds[i].properties.position);
}
birds[i].properties = Entities.getEntityProperties(birds[i].particle);
if (birds[i].properties) {
knownBirds++;
averageVelocity = Vec3.sum(averageVelocity, birds[i].properties.velocity);
averagePosition = Vec3.sum(averagePosition, birds[i].properties.position);
}
}
@ -220,7 +213,7 @@ function updateBirds(deltaTime) {
birds[i].thrust = { x: 0, y: 0, z: 0 }; // assume no thrust...
if (birds[i].particle.isKnownID) {
if (birds[i].particle) {
if (enableFlyTowardPoints) {
// if we're flying toward clusters, and the cluster changed, and this bird is flyingToward
@ -400,7 +393,7 @@ function updateBirds(deltaTime) {
for(var j =0; j < birdsInFlock; j++) {
// if this is not me, and a known bird, then check our position
if (birds[i].properties.isKnownID && j != i) {
if (birds[i].properties && j != i) {
var positionMe = birds[i].properties.position;
var positionYou = birds[j].properties.position;
var awayFromYou = Vec3.subtract(positionMe, positionYou); // vector pointing away from "you"
@ -428,7 +421,7 @@ function updateBirds(deltaTime) {
// iterate all birds again, apply their thrust
for(var i =0; i < birdsInFlock; i++) {
if (birds[i].particle.isKnownID) {
if (birds[i].particle) {
var color;
if (birds[i].gliding) {

View file

@ -29,10 +29,6 @@ function rideWithEntity(deltaTime) {
if (iteration <= lengthOfRide) {
// Check to see if we've been notified of the actual identity of the entities we created
if (!entityA.isKnownID) {
entityA = Entities.identifyEntity(entityA);
}
var propertiesA = Entities.getEntityProperties(entityA);
var newPosition = propertiesA.position;
MyAvatar.position = { x: propertiesA.position.x - 1,

View file

@ -206,15 +206,9 @@ function keyPressEvent(event) {
function cleanup() {
for (var i = 0; i < tableParts.length; i++) {
if (!tableParts[i].isKnownID) {
tableParts[i] = Entities.identifyEntity(tableParts[i]);
}
Entities.deleteEntity(tableParts[i]);
}
for (var i = 0; i < balls.length; i++) {
if (!balls[i].isKnownID) {
balls[i] = Entities.identifyEntity(balls[i]);
}
Entities.deleteEntity(balls[i]);
}
Overlays.deleteOverlay(reticle);
@ -222,18 +216,13 @@ function cleanup() {
}
function update(deltaTime) {
if (!cueBall.isKnownID) {
cueBall = Entities.identifyEntity(cueBall);
} else {
// Check if cue ball has fallen off table, re-drop if so
var cueProperties = Entities.getEntityProperties(cueBall);
if (cueProperties.position.y < tableCenter.y) {
// Replace the cueball
Entities.editEntity(cueBall, { position: cuePosition } );
// Check if cue ball has fallen off table, re-drop if so
var cueProperties = Entities.getEntityProperties(cueBall);
if (cueProperties.position.y < tableCenter.y) {
// Replace the cueball
Entities.editEntity(cueBall, { position: cuePosition } );
}
}
}
function entityCollisionWithEntity(entity1, entity2, collision) {

View file

@ -157,7 +157,7 @@ ChessGame.Piece = (function(position, dimensions, url, rotation) {
});
// Build the user data string
ChessGame.Piece.prototype.buildUserDataString = function() {
if (!(ChessGame.board !== null || ChessGame.board.entity.isKnownID)) {
if (!ChessGame.board) {
print("ChessGame.Piece.prototype.buildUserDataString(): Called before proper initialization, bailing.");
return null;
}
@ -200,9 +200,7 @@ ChessGame.scriptStarting = function() {
}
ChessGame.update = function() {
ChessGame.board.entity = Entities.identifyEntity(ChessGame.board.entity);
if (ChessGame.board.entity.isKnownID && ChessGame.pieces.length == 0) {
if (ChessGame.board.entity && ChessGame.pieces.length == 0) {
// Setup white pieces
var isWhite = true;
var row = 1;
@ -260,4 +258,4 @@ ChessGame.scriptEnding = function() {
Script.scriptEnding.connect(ChessGame.scriptEnding);
Script.update.connect(ChessGame.update);
ChessGame.scriptStarting();
ChessGame.scriptStarting();

View file

@ -183,8 +183,6 @@ function initializeInvaders() {
modelURL: invaderModels[row].modelURL,
lifetime: itemLifetimes
});
print("invaders[row][column].creatorTokenID=" + invaders[row][column].creatorTokenID);
}
}
}
@ -193,7 +191,7 @@ function moveInvaders() {
for (var row = 0; row < numberOfRows; row++) {
for (var column = 0; column < invadersPerRow; column++) {
props = Entities.getEntityProperties(invaders[row][column]);
if (props.isKnownID) {
if (props.id) {
invaderPosition = getInvaderPosition(row, column);
Entities.editEntity(invaders[row][column],
{
@ -292,7 +290,6 @@ function endGame() {
}
function moveShipTo(position) {
myShip = Entities.identifyEntity(myShip);
Entities.editEntity(myShip, { position: position });
}
@ -303,9 +300,8 @@ function fireMissile() {
// If we've fired a missile, then check to see if it's still alive
if (missileFired) {
var missileProperties = Entities.getEntityProperties(myMissile);
print("missileProperties.isKnownID=" + missileProperties.isKnownID);
if (!missileProperties.isKnownID) {
if (!missileProperties) {
print("canFire = true");
canFire = true;
}
@ -374,24 +370,21 @@ Controller.captureKeyEvents({text: " "});
function deleteIfInvader(possibleInvaderEntity) {
for (var row = 0; row < numberOfRows; row++) {
for (var column = 0; column < invadersPerRow; column++) {
invaders[row][column] = Entities.identifyEntity(invaders[row][column]);
if (invaders[row][column].isKnownID) {
if (invaders[row][column].id == possibleInvaderEntity.id) {
Entities.deleteEntity(possibleInvaderEntity);
Entities.deleteEntity(myMissile);
if (invaders[row][column].id && invaders[row][column].id == possibleInvaderEntity.id) {
Entities.deleteEntity(possibleInvaderEntity);
Entities.deleteEntity(myMissile);
// play the hit sound
var options = {};
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
z: MyAvatar.position.z + 0.0 };
} else {
options.position = getInvaderPosition(row, column);
}
Audio.playSound(hitSound, options);
// play the hit sound
var options = {};
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
z: MyAvatar.position.z + 0.0 };
} else {
options.position = getInvaderPosition(row, column);
}
Audio.playSound(hitSound, options);
}
}
}
@ -402,7 +395,6 @@ function entityCollisionWithEntity(entityA, entityB, collision) {
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
if (missileFired) {
myMissile = Entities.identifyEntity(myMissile);
if (myMissile.id == entityA.id) {
deleteIfInvader(entityB);
} else if (myMissile.id == entityB.id) {

View file

@ -42,9 +42,6 @@ function randomColor() {
function update(deltaTime) {
time += deltaTime;
if (!ball.isKnownID) {
ball = Entities.identifyEntity(ball);
}
rotation = Quat.angleAxis(time * omega /Math.PI * 180.0, { x: 0, y: 1, z: 0 });
Entities.editEntity(ball,
{

View file

@ -34,7 +34,6 @@
function onRowClicked(e) {
var id = this.dataset.entityId;
var selection = [this.dataset.entityId];
if (e.shiftKey) {
selection = selection.concat(selectedEntities);

View file

@ -21,7 +21,7 @@ EntityListTool = function(opts) {
var selectedIDs = [];
for (var i = 0; i < selectionManager.selections.length; i++) {
selectedIDs.push(selectionManager.selections[i].id);
selectedIDs.push(selectionManager.selections[i]);
}
data = {
@ -38,7 +38,7 @@ EntityListTool = function(opts) {
var id = ids[i];
var properties = Entities.getEntityProperties(id);
entities.push({
id: id.id,
id: id,
name: properties.name,
type: properties.type,
url: properties.type == "Model" ? properties.modelURL : "",
@ -47,7 +47,7 @@ EntityListTool = function(opts) {
var selectedIDs = [];
for (var i = 0; i < selectionManager.selections.length; i++) {
selectedIDs.push(selectionManager.selections[i].id);
selectedIDs.push(selectionManager.selections[i].id); // ?
}
var data = {
@ -64,11 +64,7 @@ EntityListTool = function(opts) {
var ids = data.entityIds;
var entityIDs = [];
for (var i = 0; i < ids.length; i++) {
entityIDs.push({
id: ids[i],
isKnownID: true,
creatorTokenID: 0,
});
entityIDs.push(ids[i]);
}
selectionManager.setSelections(entityIDs);
if (data.focus) {

View file

@ -19,15 +19,8 @@ SPACE_WORLD = "world";
SelectionManager = (function() {
var that = {};
var PENDING_SELECTION_CHECK_INTERVAL = 50;
that.savedProperties = {};
that.selections = [];
// These are selections that don't have a known ID yet
that.pendingSelections = [];
var pendingSelectionTimer = null;
var listeners = [];
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
@ -45,7 +38,7 @@ SelectionManager = (function() {
that.savedProperties = {};
for (var i = 0; i < that.selections.length; i++) {
var entityID = that.selections[i];
that.savedProperties[entityID.id] = Entities.getEntityProperties(entityID);
that.savedProperties[entityID] = Entities.getEntityProperties(entityID);
}
};
@ -61,41 +54,17 @@ SelectionManager = (function() {
that.selections = [];
for (var i = 0; i < entityIDs.length; i++) {
var entityID = entityIDs[i];
if (entityID.isKnownID) {
that.selections.push(entityID);
} else {
that.pendingSelections.push(entityID);
if (pendingSelectionTimer == null) {
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
}
}
that.selections.push(entityID);
}
that._update();
};
that._checkPendingSelections = function() {
for (var i = 0; i < that.pendingSelections.length; i++) {
var entityID = that.pendingSelections[i];
var newEntityID = Entities.identifyEntity(entityID);
if (newEntityID.isKnownID) {
that.pendingSelections.splice(i, 1);
that.addEntity(newEntityID);
i--;
}
}
if (that.pendingSelections.length == 0) {
Script.clearInterval(pendingSelectionTimer);
pendingSelectionTimer = null;
}
}
that.addEntity = function(entityID, toggleSelection) {
if (entityID.isKnownID) {
if (entityID) {
var idx = -1;
for (var i = 0; i < that.selections.length; i++) {
if (entityID.id == that.selections[i].id) {
if (entityID == that.selections[i]) {
idx = i;
break;
}
@ -105,14 +74,6 @@ SelectionManager = (function() {
} else if (toggleSelection) {
that.selections.splice(idx, 1);
}
} else {
var idx = that.pendingSelections.indexOf(entityID);
if (idx == -1) {
that.pendingSelections.push(entityID);
if (pendingSelectionTimer == null) {
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
}
}
}
that._update();
@ -123,24 +84,11 @@ SelectionManager = (function() {
if (idx >= 0) {
that.selections.splice(idx, 1);
}
var idx = that.pendingSelections.indexOf(entityID);
if (idx >= 0) {
that.pendingSelections.splice(idx, 1);
}
that._update();
};
that.clearSelections = function() {
that.selections = [];
that.pendingSelections = [];
if (pendingSelectionTimer !== null) {
Script.clearInterval(pendingSelectionTimer);
pendingSelectionTimer = null;
}
that._update();
};
@ -1563,7 +1511,7 @@ SelectionDisplay = (function () {
var wantDebug = false;
for (var i = 0; i < SelectionManager.selections.length; i++) {
var properties = SelectionManager.savedProperties[SelectionManager.selections[i].id];
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z });
Entities.editEntity(SelectionManager.selections[i], {
position: newPosition,
@ -1641,7 +1589,7 @@ SelectionDisplay = (function () {
}
for (var i = 0; i < SelectionManager.selections.length; i++) {
var id = SelectionManager.selections[i];
var properties = selectionManager.savedProperties[id.id];
var properties = selectionManager.savedProperties[id];
var original = properties.position;
var newPosition = Vec3.sum(properties.position, vector);
@ -1900,7 +1848,7 @@ SelectionDisplay = (function () {
vector = change;
Vec3.print("Radius stretch: ", vector);
var length = vector.x + vector.y + vector.z;
var props = selectionManager.savedProperties[selectionManager.selections[0].id];
var props = selectionManager.savedProperties[selectionManager.selections[0]];
var radius = props.dimensions.z / 2;
var originalCutoff = props.cutoff;
@ -1917,7 +1865,7 @@ SelectionDisplay = (function () {
};
function radiusStretchFunc(vector, change) {
var props = selectionManager.savedProperties[selectionManager.selections[0].id];
var props = selectionManager.savedProperties[selectionManager.selections[0]];
// Find the axis being adjusted
var size;
@ -2084,7 +2032,7 @@ SelectionDisplay = (function () {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var properties = Entities.getEntityProperties(entityID);
var initialProperties = SelectionManager.savedProperties[entityID.id];
var initialProperties = SelectionManager.savedProperties[entityID];
var newProperties = {
rotation: Quat.multiply(yawChange, initialProperties.rotation),
@ -2211,7 +2159,7 @@ SelectionDisplay = (function () {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var properties = Entities.getEntityProperties(entityID);
var initialProperties = SelectionManager.savedProperties[entityID.id];
var initialProperties = SelectionManager.savedProperties[entityID];
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
dPos = Vec3.multiplyQbyV(pitchChange, dPos);
@ -2331,7 +2279,7 @@ SelectionDisplay = (function () {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var properties = Entities.getEntityProperties(entityID);
var initialProperties = SelectionManager.savedProperties[entityID.id];
var initialProperties = SelectionManager.savedProperties[entityID];
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
dPos = Vec3.multiplyQbyV(rollChange, dPos);

View file

@ -12,17 +12,17 @@ LightOverlayManager = function() {
// List of overlays not currently being used
var unusedOverlays = [];
// Map from EntityItemID.id to overlay id
// Map from EntityItemID to overlay id
var entityOverlays = {};
// Map from EntityItemID.id to EntityItemID object
// Map from EntityItemID to EntityItemID object
var entityIDs = {};
this.updatePositions = function(ids) {
for (var id in entityIDs) {
var entityID = entityIDs[id];
var properties = Entities.getEntityProperties(entityID);
Overlays.editOverlay(entityOverlays[entityID.id], {
Overlays.editOverlay(entityOverlays[entityID], {
position: properties.position
});
}
@ -77,10 +77,10 @@ LightOverlayManager = function() {
function addEntity(entityID) {
var properties = Entities.getEntityProperties(entityID);
if (properties.type == "Light" && !(entityID.id in entityOverlays)) {
if (properties.type == "Light" && !(entityID in entityOverlays)) {
var overlay = getOverlay();
entityOverlays[entityID.id] = overlay;
entityIDs[entityID.id] = entityID;
entityOverlays[entityID] = overlay;
entityIDs[entityID] = entityID;
Overlays.editOverlay(overlay, {
position: properties.position,
url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL,
@ -94,20 +94,12 @@ LightOverlayManager = function() {
}
function deleteEntity(entityID) {
if (entityID.id in entityOverlays) {
releaseOverlay(entityOverlays[entityID.id]);
delete entityOverlays[entityID.id];
if (entityID in entityOverlays) {
releaseOverlay(entityOverlays[entityID]);
delete entityOverlays[entityID];
}
}
function changeEntityID(oldEntityID, newEntityID) {
entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id];
entityIDs[newEntityID.id] = newEntityID;
delete entityOverlays[oldEntityID.id];
delete entityIDs[oldEntityID.id];
}
function clearEntities() {
for (var id in entityOverlays) {
releaseOverlay(entityOverlays[id]);
@ -117,7 +109,6 @@ LightOverlayManager = function() {
}
Entities.addingEntity.connect(addEntity);
Entities.changingEntityID.connect(changeEntityID);
Entities.deletingEntity.connect(deleteEntity);
Entities.clearingEntities.connect(clearEntities);

View file

@ -316,7 +316,7 @@ function addIndicators(modelID) {
modelID.properties.sittingPoints[i].indicator = new SeatIndicator(modelID.properties, i);
}
models[modelID.id] = modelID;
models[modelID] = modelID;
} else {
Entities.editEntity(modelID, { glowLevel: 0.0 });
}
@ -326,7 +326,7 @@ function removeIndicators(modelID) {
for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) {
modelID.properties.sittingPoints[i].indicator.cleanup();
}
delete models[modelID.id];
delete models[modelID];
}
function showIndicators(doShow) {

View file

@ -82,11 +82,6 @@ void DatagramProcessor::processDatagrams() {
break;
}
case PacketTypeEntityAddResponse:
// this will keep creatorTokenIDs to IDs mapped correctly
EntityItemID::handleAddEntityResponse(incomingPacket);
application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
break;
case PacketTypeEntityData:
case PacketTypeEntityErase:
case PacketTypeOctreeStats:

View file

@ -66,8 +66,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
}
EntityTreeRenderer::~EntityTreeRenderer() {
@ -961,7 +961,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi
}
// makes it the unknown ID, we just released so we can't be clicking on anything
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID();
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
_lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true;
}
@ -1041,7 +1041,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs);
}
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
}
}

View file

@ -98,7 +98,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
return;
}
if (intersection.entityID.id == getID()) {
if (intersection.entityID == getID()) {
if (event->button() == Qt::MouseButton::RightButton) {
if (event->type() == QEvent::MouseButtonRelease) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {

View file

@ -21,7 +21,7 @@
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type,
unsigned char* editBuffer, size_t length, int clockSkew) {
if (type == PacketTypeEntityAddOrEdit) {
if (type == PacketTypeEntityAdd || type == PacketTypeEntityEdit) {
EntityItem::adjustEditPacketForClockSkew(editBuffer, length, clockSkew);
}
}

View file

@ -30,9 +30,7 @@ bool EntityItem::_sendPhysicsUpdates = true;
EntityItem::EntityItem(const EntityItemID& entityItemID) :
_type(EntityTypes::Unknown),
_id(entityItemID.id),
_creatorTokenID(entityItemID.creatorTokenID),
_newlyCreated(false),
_id(entityItemID),
_lastSimulated(0),
_lastUpdated(0),
_lastEdited(0),
@ -351,8 +349,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// id
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
_id = QUuid::fromRfc4122(encodedID);
_creatorTokenID = UNKNOWN_ENTITY_TOKEN; // if we know the id, then we don't care about the creator token
_newlyCreated = false;
dataAt += encodedID.size();
bytesRead += encodedID.size();

View file

@ -96,11 +96,7 @@ public:
// ID and EntityItemID related methods
const QUuid& getID() const { return _id; }
void setID(const QUuid& id) { _id = id; }
uint32_t getCreatorTokenID() const { return _creatorTokenID; }
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
bool isNewlyCreated() const { return _newlyCreated; }
bool isKnownID() const { return getID() != UNKNOWN_ENTITY_ID; }
EntityItemID getEntityItemID() const { return EntityItemID(getID(), getCreatorTokenID(), getID() != UNKNOWN_ENTITY_ID); }
EntityItemID getEntityItemID() const { return EntityItemID(_id); }
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
@ -356,8 +352,6 @@ protected:
static bool _sendPhysicsUpdates;
EntityTypes::EntityType _type;
QUuid _id;
uint32_t _creatorTokenID;
bool _newlyCreated;
quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes
quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes
quint64 _lastEdited; // last official local or remote edit time

View file

@ -14,130 +14,42 @@
#include <PacketHeaders.h>
#include "RegisteredMetaTypes.h"
#include "EntityItemID.h"
// for locally created models
QHash<uint32_t, QUuid> EntityItemID::_tokenIDsToIDs;
uint32_t EntityItemID::_nextCreatorTokenID = 0;
EntityItemID::EntityItemID() :
id(NEW_ENTITY),
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
isKnownID(false)
{
}
EntityItemID::EntityItemID(const EntityItemID& other) :
id(other.id),
creatorTokenID(other.creatorTokenID),
isKnownID(other.isKnownID)
EntityItemID::EntityItemID() : QUuid()
{
}
EntityItemID::EntityItemID(const QUuid& id, uint32_t creatorTokenID, bool isKnownID) :
id(id),
creatorTokenID(creatorTokenID),
isKnownID(isKnownID)
{
};
EntityItemID::EntityItemID(const QUuid& id) :
id(id),
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
isKnownID(true)
{
};
EntityItemID EntityItemID::getIDfromCreatorTokenID(uint32_t creatorTokenID) {
if (_tokenIDsToIDs.find(creatorTokenID) != _tokenIDsToIDs.end()) {
return EntityItemID(_tokenIDsToIDs[creatorTokenID], creatorTokenID, true);
}
return EntityItemID(UNKNOWN_ENTITY_ID);
EntityItemID::EntityItemID(const QUuid& id) : QUuid(id)
{
}
uint32_t EntityItemID::getNextCreatorTokenID() {
uint32_t creatorTokenID = _nextCreatorTokenID;
_nextCreatorTokenID++;
return creatorTokenID;
}
EntityItemID EntityItemID::assignActualIDForToken() const {
EntityItemID newlyAssignedEntityID;
newlyAssignedEntityID.creatorTokenID = creatorTokenID;
newlyAssignedEntityID.isKnownID = true;
newlyAssignedEntityID.id = QUuid::createUuid();
return newlyAssignedEntityID;
}
EntityItemID EntityItemID::convertToKnownIDVersion() const {
EntityItemID knownIDVersionEntityID;
knownIDVersionEntityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
knownIDVersionEntityID.isKnownID = true;
knownIDVersionEntityID.id = id;
return knownIDVersionEntityID;
}
EntityItemID EntityItemID::convertToCreatorTokenVersion() const {
EntityItemID knownIDVersionEntityID;
knownIDVersionEntityID.creatorTokenID = creatorTokenID;
knownIDVersionEntityID.isKnownID = false;
knownIDVersionEntityID.id = UNKNOWN_ENTITY_ID;
return knownIDVersionEntityID;
}
// EntityItemID::EntityItemID(const EntityItemID& other) : QUuid(other)
// {
// }
EntityItemID EntityItemID::readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead) {
EntityItemID result;
if (bytesLeftToRead >= NUM_BYTES_RFC4122_UUID) {
// id
QByteArray encodedID((const char*)data, NUM_BYTES_RFC4122_UUID);
result.id = QUuid::fromRfc4122(encodedID);
result.isKnownID = true;
result.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
result = QUuid::fromRfc4122(encodedID);
}
return result;
}
void EntityItemID::handleAddEntityResponse(const QByteArray& packet) {
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data());
int numBytesPacketHeader = numBytesForPacketHeader(packet);
int bytesRead = numBytesPacketHeader;
dataAt += numBytesPacketHeader;
uint32_t creatorTokenID;
memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
dataAt += sizeof(creatorTokenID);
bytesRead += sizeof(creatorTokenID);
QUuid entityID = QUuid::fromRfc4122(packet.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
dataAt += NUM_BYTES_RFC4122_UUID;
// add our token to id mapping
_tokenIDsToIDs[creatorTokenID] = entityID;
}
QScriptValue EntityItemID::toScriptValue(QScriptEngine* engine) const {
return EntityItemIDtoScriptValue(engine, *this);
}
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& id) {
QScriptValue obj = engine->newObject();
obj.setProperty("id", id.id.toString());
obj.setProperty("creatorTokenID", id.creatorTokenID);
obj.setProperty("isKnownID", id.isKnownID);
return obj;
return quuidToScriptValue(engine, id);
}
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
id.id = QUuid(object.property("id").toVariant().toString());
id.creatorTokenID = object.property("creatorTokenID").toVariant().toUInt();
id.isKnownID = object.property("isKnownID").toVariant().toBool();
quuidFromScriptValue(object, id);
}

View file

@ -20,87 +20,40 @@
#include <QScriptEngine>
#include <QUuid>
const uint32_t UNKNOWN_ENTITY_TOKEN = 0xFFFFFFFF;
const QUuid UNKNOWN_ENTITY_ID; // null uuid
//const uint32_t NEW_ENTITY = 0xFFFFFFFF;
//const uint32_t UNKNOWN_ENTITY_ID = 0xFFFFFFFF;
const QUuid NEW_ENTITY;
const QUuid UNKNOWN_ENTITY_ID;
/// Abstract ID for editing model items. Used in EntityItem JS API - When models are created in the JS api, they are given a
/// local creatorTokenID, the actual id for the model is not known until the server responds to the creator with the
/// correct mapping. This class works with the scripting API an allows the developer to edit models they created.
class EntityItemID {
/// Abstract ID for editing model items. Used in EntityItem JS API.
class EntityItemID : public QUuid {
public:
EntityItemID();
EntityItemID(const EntityItemID& other);
EntityItemID(const QUuid& id, uint32_t creatorTokenID, bool isKnownID);
EntityItemID(const QUuid& id);
//uint32_t id;
QUuid id;
uint32_t creatorTokenID;
bool isKnownID;
// these methods will reduce the ID down to half the IDs data to allow for comparisons and searches of known values
EntityItemID convertToKnownIDVersion() const;
EntityItemID convertToCreatorTokenVersion() const;
bool isInvalidID() const { return id == UNKNOWN_ENTITY_ID && creatorTokenID == UNKNOWN_ENTITY_TOKEN && isKnownID == false; }
// these methods allow you to create models, and later edit them.
static EntityItemID createInvalidEntityID() { return EntityItemID(UNKNOWN_ENTITY_ID, UNKNOWN_ENTITY_TOKEN, false); }
static EntityItemID getIDfromCreatorTokenID(uint32_t creatorTokenID);
static uint32_t getNextCreatorTokenID();
static void handleAddEntityResponse(const QByteArray& packet);
// EntityItemID(const EntityItemID& other);
static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead);
QScriptValue toScriptValue(QScriptEngine* engine) const;
private:
friend class EntityTree;
EntityItemID assignActualIDForToken() const; // only called by EntityTree
static uint32_t _nextCreatorTokenID; /// used by the static interfaces for creator token ids
static QHash<uint32_t, QUuid> _tokenIDsToIDs;
bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; }
// QUuid id;
};
inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
return (a.id == b.id) ? (a.creatorTokenID < b.creatorTokenID) : (a.id < b.id);
}
// inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
// return a.id < b.id;
// }
inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
if (a.isInvalidID() && b.isInvalidID()) {
return true;
}
if (a.isInvalidID() != b.isInvalidID()) {
return false;
}
if (a.id == UNKNOWN_ENTITY_ID || b.id == UNKNOWN_ENTITY_ID) {
return a.creatorTokenID == b.creatorTokenID;
}
return a.id == b.id;
}
// inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
// return a.id == b.id;
// }
inline bool operator!=(const EntityItemID& a, const EntityItemID& b) {
return !(a == b);
}
// inline bool operator!=(const EntityItemID& a, const EntityItemID& b) {
// return !(a == b);
// }
inline uint qHash(const EntityItemID& a, uint seed) {
QUuid temp;
if (a.id == UNKNOWN_ENTITY_ID) {
temp = QUuid(a.creatorTokenID,0,0,0,0,0,0,0,0,0,0);
} else {
temp = a.id;
}
return qHash(temp, seed);
}
// inline uint qHash(const EntityItemID& a, uint seed) {
// return qHash(a.id, seed);
// }
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
debug << "[ id:" << id.id << ", creatorTokenID:" << id.creatorTokenID << ", isKnownID:" << id.isKnownID << "]";
debug << "[entity-id:" << id.toString() << "]";
return debug;
}

View file

@ -350,9 +350,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
if (_idSet) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(isKnownID, (_id != UNKNOWN_ENTITY_ID));
} else {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(isKnownID, false);
}
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
@ -561,7 +558,7 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
// TODO: Implement support for script and visible properties.
//
bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too.
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
@ -586,23 +583,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
if (success) {
// Now add our edit content details...
bool isNewEntityItem = (id.id == NEW_ENTITY);
// id
// encode our ID as a byte count coded byte stream
QByteArray encodedID = id.id.toRfc4122(); // NUM_BYTES_RFC4122_UUID
QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID
// encode our ID as a byte count coded byte stream
ByteCountCoded<quint32> tokenCoder;
QByteArray encodedToken;
// special case for handling "new" modelItems
if (isNewEntityItem) {
// encode our creator token as a byte count coded byte stream
tokenCoder = id.creatorTokenID;
encodedToken = tokenCoder;
}
// encode our type as a byte count coded byte stream
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
QByteArray encodedType = typeCoder;
@ -631,7 +620,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
bool successLastEditedFits = packetData->appendValue(lastEdited);
bool successIDFits = packetData->appendValue(encodedID);
if (isNewEntityItem && successIDFits) {
if (successIDFits) {
successIDFits = packetData->appendValue(encodedToken);
}
bool successTypeFits = packetData->appendValue(encodedType);
@ -829,7 +818,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
// TODO: Implement support for script and visible properties.
//
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties) {
EntityItemID& entityID, EntityItemProperties& properties) {
bool valid = false;
const unsigned char* dataAt = data;
@ -863,36 +852,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
dataAt += encodedID.size();
processedBytes += encodedID.size();
bool isNewEntityItem = (editID == NEW_ENTITY);
if (isNewEntityItem) {
// If this is a NEW_ENTITY, then we assume that there's an additional uint32_t creatorToken, that
// we want to send back to the creator as an map to the actual id
QByteArray encodedToken((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint32> tokenCoder = encodedToken;
quint32 creatorTokenID = tokenCoder;
encodedToken = tokenCoder; // determine true bytesToRead
dataAt += encodedToken.size();
processedBytes += encodedToken.size();
//newEntityItem.setCreatorTokenID(creatorTokenID);
//newEntityItem._newlyCreated = true;
entityID.id = NEW_ENTITY;
entityID.creatorTokenID = creatorTokenID;
entityID.isKnownID = false;
valid = true;
// created time is lastEdited time
properties.setCreated(lastEdited);
} else {
entityID.id = editID;
entityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
entityID.isKnownID = true;
valid = true;
}
entityID = editID;
valid = true;
// Entity Type...
QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
@ -1015,7 +976,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
// header it does not include the send times and sequence number because that is handled by the
// edit packet sender...
bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID,
unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) {
unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) {
unsigned char* copyAt = outputBuffer;
uint16_t numberOfIds = 1; // only one entity ID in this message
@ -1029,7 +990,7 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt
copyAt += sizeof(numberOfIds);
outputLength = sizeof(numberOfIds);
QUuid entityID = entityItemID.id;
QUuid entityID = entityItemID;
QByteArray encodedEntityID = entityID.toRfc4122();
memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID);

View file

@ -70,9 +70,6 @@ public:
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
EntityPropertyFlags getChangedProperties() const;
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
AACube getMaximumAACube() const;
AABox getAABox() const;

View file

@ -20,7 +20,6 @@
EntityScriptingInterface::EntityScriptingInterface() :
_nextCreatorTokenID(0),
_entityTree(NULL)
{
auto nodeList = DependencyManager::get<NodeList>();
@ -29,7 +28,7 @@ EntityScriptingInterface::EntityScriptingInterface() :
}
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
EntityItemID entityID, const EntityItemProperties& properties) {
EntityItemID entityID, const EntityItemProperties& properties) {
getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties);
}
@ -47,7 +46,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
if (_entityTree) {
disconnect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
disconnect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
disconnect(_entityTree, &EntityTree::changingEntityID, this, &EntityScriptingInterface::changingEntityID);
disconnect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
}
@ -56,7 +54,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
if (_entityTree) {
connect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
connect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
connect(_entityTree, &EntityTree::changingEntityID, this, &EntityScriptingInterface::changingEntityID);
connect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
}
}
@ -71,14 +68,11 @@ void bidForSimulationOwnership(EntityItemProperties& properties) {
EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
// The application will keep track of creatorTokenID
uint32_t creatorTokenID = EntityItemID::getNextCreatorTokenID();
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
EntityItemProperties propertiesWithSimID = properties;
EntityItemID id(NEW_ENTITY, creatorTokenID, false);
EntityItemID id = EntityItemID(QUuid::createUuid());
// If we have a local entity tree set, then also update it.
bool success = true;
@ -98,34 +92,17 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
// queue the packet
if (success) {
queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID);
queueEntityMessage(PacketTypeEntityAdd, id, propertiesWithSimID);
}
return id;
}
EntityItemID EntityScriptingInterface::identifyEntity(EntityItemID entityID) {
EntityItemID actualID = entityID;
if (!entityID.isKnownID) {
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
if (actualID == UNKNOWN_ENTITY_ID) {
return entityID; // bailing early
}
// found it!
entityID.id = actualID.id;
entityID.isKnownID = true;
}
return entityID;
}
EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID entityID) {
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {
EntityItemProperties results;
EntityItemID identity = identifyEntity(entityID);
if (_entityTree) {
_entityTree->lockForRead();
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(identity));
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(EntityItemID(identity)));
if (entity) {
results = entity->getProperties();
@ -142,8 +119,6 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID
}
}
} else {
results.setIsUnknownID();
}
_entityTree->unlock();
}
@ -151,67 +126,42 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID
return results;
}
EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const EntityItemProperties& properties) {
EntityItemID actualID = entityID;
// if the entity is unknown, attempt to look it up
if (!entityID.isKnownID) {
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
if (actualID.id != UNKNOWN_ENTITY_ID) {
entityID.id = actualID.id;
entityID.isKnownID = true;
}
}
// If we have a local entity tree set, then also update it. We can do this even if we don't know
// the actual id, because we can edit out local entities just with creatorTokenID
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties) {
EntityItemID entityID(id);
// If we have a local entity tree set, then also update it.
if (_entityTree) {
_entityTree->lockForWrite();
_entityTree->updateEntity(entityID, properties);
_entityTree->unlock();
}
// if at this point, we know the id, send the update to the entity server
if (entityID.isKnownID) {
// make sure the properties has a type, so that the encode can know which properties to include
if (properties.getType() == EntityTypes::Unknown) {
EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
// we need to change the outgoing properties, so we make a copy, modify, and send.
EntityItemProperties modifiedProperties = properties;
entity->setLastBroadcast(usecTimestampNow());
modifiedProperties.setType(entity->getType());
bidForSimulationOwnership(modifiedProperties);
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, modifiedProperties);
return entityID;
}
// make sure the properties has a type, so that the encode can know which properties to include
if (properties.getType() == EntityTypes::Unknown) {
EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
// we need to change the outgoing properties, so we make a copy, modify, and send.
EntityItemProperties modifiedProperties = properties;
entity->setLastBroadcast(usecTimestampNow());
modifiedProperties.setType(entity->getType());
bidForSimulationOwnership(modifiedProperties);
queueEntityMessage(PacketTypeEntityEdit, entityID, modifiedProperties);
return id;
}
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
}
return entityID;
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
return id;
}
void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
EntityItemID actualID = entityID;
// if the entity is unknown, attempt to look it up
if (!entityID.isKnownID) {
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
if (actualID.id != UNKNOWN_ENTITY_ID) {
entityID.id = actualID.id;
entityID.isKnownID = true;
}
}
void EntityScriptingInterface::deleteEntity(QUuid id) {
EntityItemID entityID(id);
bool shouldDelete = true;
// If we have a local entity tree set, then also update it.
if (_entityTree) {
_entityTree->lockForWrite();
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(actualID));
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(entityID));
if (entity) {
if (entity->getLocked()) {
shouldDelete = false;
@ -224,13 +174,13 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
}
// if at this point, we know the id, and we should still delete the entity, send the update to the entity server
if (shouldDelete && entityID.isKnownID) {
if (shouldDelete) {
getEntityPacketSender()->queueEraseEntityMessage(entityID);
}
}
EntityItemID EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
EntityItemID result(UNKNOWN_ENTITY_ID, UNKNOWN_ENTITY_TOKEN, false);
QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
EntityItemID result;
if (_entityTree) {
_entityTree->lockForRead();
const EntityItem* closestEntity = _entityTree->findClosestEntity(center, radius);
@ -251,8 +201,8 @@ void EntityScriptingInterface::dumpTree() const {
}
}
QVector<EntityItemID> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
QVector<EntityItemID> result;
QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
QVector<QUuid> result;
if (_entityTree) {
_entityTree->lockForRead();
QVector<const EntityItem*> entities;
@ -266,8 +216,8 @@ QVector<EntityItemID> EntityScriptingInterface::findEntities(const glm::vec3& ce
return result;
}
QVector<EntityItemID> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const {
QVector<EntityItemID> result;
QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const {
QVector<QUuid> result;
if (_entityTree) {
_entityTree->lockForRead();
AABox box(corner, dimensions);
@ -403,9 +353,8 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
value.intersects = object.property("intersects").toVariant().toBool();
value.accurate = object.property("accurate").toVariant().toBool();
QScriptValue entityIDValue = object.property("entityID");
if (entityIDValue.isValid()) {
EntityItemIDfromScriptValue(entityIDValue, value.entityID);
}
// EntityItemIDfromScriptValue(entityIDValue, value.entityID);
quuidFromScriptValue(entityIDValue, value.entityID);
QScriptValue entityPropertiesValue = object.property("properties");
if (entityPropertiesValue.isValid()) {
EntityItemPropertiesFromScriptValue(entityPropertiesValue, value.properties);

View file

@ -34,7 +34,7 @@ public:
RayToEntityIntersectionResult();
bool intersects;
bool accurate;
EntityItemID entityID;
QUuid entityID;
EntityItemProperties properties;
float distance;
BoxFace face;
@ -70,34 +70,31 @@ public slots:
Q_INVOKABLE bool canRez();
/// adds a model with the specific properties
Q_INVOKABLE EntityItemID addEntity(const EntityItemProperties& properties);
/// identify a recently created model to determine its true ID
Q_INVOKABLE EntityItemID identifyEntity(EntityItemID entityID);
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties);
/// gets the current model properties for a specific model
/// this function will not find return results in script engine contexts which don't have access to models
Q_INVOKABLE EntityItemProperties getEntityProperties(EntityItemID entityID);
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID);
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
/// successful edit, if the input entityID is for an unknown model this function will have no effect
Q_INVOKABLE EntityItemID editEntity(EntityItemID entityID, const EntityItemProperties& properties);
Q_INVOKABLE QUuid editEntity(QUuid entityID, const EntityItemProperties& properties);
/// deletes a model
Q_INVOKABLE void deleteEntity(EntityItemID entityID);
Q_INVOKABLE void deleteEntity(QUuid entityID);
/// finds the closest model to the center point, within the radius
/// will return a EntityItemID.isKnownID = false if no models are in the radius
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE EntityItemID findClosestEntity(const glm::vec3& center, float radius) const;
Q_INVOKABLE QUuid findClosestEntity(const glm::vec3& center, float radius) const;
/// finds models within the search sphere specified by the center point and radius
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<EntityItemID> findEntities(const glm::vec3& center, float radius) const;
Q_INVOKABLE QVector<QUuid> findEntities(const glm::vec3& center, float radius) const;
/// finds models within the search sphere specified by the center point and radius
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<EntityItemID> findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
Q_INVOKABLE QVector<QUuid> findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
/// If the scripting context has visible entities, this will determine a ray intersection, the results
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
@ -145,7 +142,6 @@ signals:
void deletingEntity(const EntityItemID& entityID);
void addingEntity(const EntityItemID& entityID);
void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID);
void clearingEntities();
private:
@ -155,7 +151,6 @@ private:
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
bool precisionPicking);
uint32_t _nextCreatorTokenID;
EntityTree* _entityTree;
};

View file

@ -65,7 +65,8 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
bool EntityTree::handlesEditPacketType(PacketType packetType) const {
// we handle these types of "edit" packets
switch (packetType) {
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityAdd:
case PacketTypeEntityEdit:
case PacketTypeEntityErase:
return true;
default:
@ -230,19 +231,11 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
}
}
// NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems
// that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs.
bool recordCreationTime = false;
if (!entityID.isKnownID) {
if (getIsServer()) {
qCDebug(entities) << "UNEXPECTED!!! ----- EntityTree::addEntity()... (getIsSever() && !entityID.isKnownID)";
return result;
}
if (properties.getCreated() == UNKNOWN_CREATED_TIME) {
// the entity's creation time was not specified in properties, which means this is a NEW entity
// and we must record its creation time
recordCreationTime = true;
}
if (properties.getCreated() == UNKNOWN_CREATED_TIME) {
// the entity's creation time was not specified in properties, which means this is a NEW entity
// and we must record its creation time
recordCreationTime = true;
}
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
@ -375,7 +368,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
// set up the deleted entities ID
quint64 deletedAt = usecTimestampNow();
_recentlyDeletedEntitiesLock.lockForWrite();
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID().id);
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID());
_recentlyDeletedEntitiesLock.unlock();
}
@ -389,95 +382,6 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
}
}
/// This method is used to find and fix entity IDs that are shifting from creator token based to known ID based entity IDs.
/// This should only be used on a client side (viewing) tree. The typical usage is that a local editor has been creating
/// entities in the local tree, those entities have creatorToken based entity IDs. But those entity edits are also sent up to
/// the server, and the server eventually sends back to the client two messages that can come in varying order. The first
/// message would be a typical query/viewing data message conversation in which the viewer "sees" the newly created entity.
/// Those entities that have been seen, will have the authoritative "known ID". Therefore there is a potential that there can
/// be two copies of the same entity in the tree: the "local only" "creator token" version of the entity and the "seen"
/// "knownID" version of the entity. The server also sends an "entityAdded" message to the client which contains the mapping
/// of the creator token to the known ID. These messages can come in any order, so we need to handle the follow cases:
///
/// Case A: The local edit occurs, the addEntity message arrives, the "viewed data" has not yet arrived.
/// In this case, we can expect that our local tree has only one copy of the entity (the creator token),
/// and we only really need to fix up that entity with a new version of the ID that includes the knownID
///
/// Case B: The local edit occurs, the "viewed data" for the new entity arrives, then the addEntity message arrives.
/// In this case, we can expect that our local tree has two copies of the entity (the creator token, and the
/// known ID version). We end up with two version of the entity because the server sends viewers only the
/// known ID version without a creator token. And we don't yet know the mapping until we get the mapping message.
/// In this case we need to fix up that entity with a new version of the ID that includes the knownID and
/// we need to delete the extra copy of the entity.
///
/// This method handles both of these cases.
///
/// NOTE: unlike some operations on the tree, this process does not mark the tree as being changed. This is because
/// we're not changing the content of the tree, we're only changing the internal IDs that map entities from creator
/// based to known IDs. This means we don't have to recurse the tree to mark the changed path as dirty.
void EntityTree::handleAddEntityResponse(const QByteArray& packet) {
if (!getIsClient()) {
qCDebug(entities) << "UNEXPECTED!!! EntityTree::handleAddEntityResponse() with !getIsClient() ***";
return;
}
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data());
int numBytesPacketHeader = numBytesForPacketHeader(packet);
int bytesRead = numBytesPacketHeader;
dataAt += numBytesPacketHeader;
uint32_t creatorTokenID;
memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
dataAt += sizeof(creatorTokenID);
bytesRead += sizeof(creatorTokenID);
QUuid entityID = QUuid::fromRfc4122(packet.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
dataAt += NUM_BYTES_RFC4122_UUID;
// First, look for the existing entity in the tree..
EntityItemID searchEntityID;
searchEntityID.id = entityID;
searchEntityID.creatorTokenID = creatorTokenID;
lockForWrite();
// find the creator token version, it's containing element, and the entity itself
EntityItem* foundEntity = NULL;
EntityItemID creatorTokenVersion = searchEntityID.convertToCreatorTokenVersion();
EntityItemID knownIDVersion = searchEntityID.convertToKnownIDVersion();
_changedEntityIDs[creatorTokenVersion] = knownIDVersion;
// First look for and find the "viewed version" of this entity... it's possible we got
// the known ID version sent to us between us creating our local version, and getting this
// remapping message. If this happened, we actually want to find and delete that version of
// the entity.
EntityTreeElement* knownIDVersionContainingElement = getContainingElement(knownIDVersion);
if (knownIDVersionContainingElement) {
foundEntity = knownIDVersionContainingElement->getEntityWithEntityItemID(knownIDVersion);
if (foundEntity) {
knownIDVersionContainingElement->removeEntityWithEntityItemID(knownIDVersion);
setContainingElement(knownIDVersion, NULL);
}
}
EntityTreeElement* creatorTokenContainingElement = getContainingElement(creatorTokenVersion);
if (creatorTokenContainingElement) {
foundEntity = creatorTokenContainingElement->getEntityWithEntityItemID(creatorTokenVersion);
if (foundEntity) {
creatorTokenContainingElement->updateEntityItemID(creatorTokenVersion, knownIDVersion);
setContainingElement(creatorTokenVersion, NULL);
setContainingElement(knownIDVersion, creatorTokenContainingElement);
// because the ID of the entity is switching, we need to emit these signals for any
// listeners who care about the changing of IDs
emit changingEntityID(creatorTokenVersion, knownIDVersion);
}
}
unlock();
}
class FindNearPointArgs {
public:
@ -635,30 +539,12 @@ EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /
EntityTreeElement* containingElement = getContainingElement(entityID);
if (containingElement) {
foundEntity = containingElement->getEntityWithEntityItemID(entityID);
if (!foundEntity && _changedEntityIDs.contains(entityID)) {
foundEntity = containingElement->getEntityWithEntityItemID(_changedEntityIDs[entityID]);
}
}
return foundEntity;
}
EntityItemID EntityTree::assignEntityID(const EntityItemID& entityItemID) {
if (!getIsServer()) {
qCDebug(entities) << "UNEXPECTED!!! assignEntityID should only be called on a server tree. entityItemID:" << entityItemID;
return entityItemID;
}
if (getContainingElement(entityItemID)) {
qCDebug(entities) << "UNEXPECTED!!! don't call assignEntityID() for existing entityIDs. entityItemID:" << entityItemID;
return entityItemID;
}
// The EntityItemID is responsible for assigning actual IDs and keeping track of them.
return entityItemID.assignActualIDForToken();
}
int EntityTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
if (!getIsServer()) {
qCDebug(entities) << "UNEXPECTED!!! processEditPacketData() should only be called on a server tree.";
@ -674,40 +560,34 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
break;
}
case PacketTypeEntityAddOrEdit: {
case PacketTypeEntityAdd:
case PacketTypeEntityEdit: {
EntityItemID entityItemID;
EntityItemProperties properties;
bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength,
processedBytes, entityItemID, properties);
processedBytes, entityItemID, properties);
// If we got a valid edit packet, then it could be a new entity or it could be an update to
// an existing entity... handle appropriately
if (validEditPacket) {
// If this is a knownID, then it should exist in our tree
if (entityItemID.isKnownID) {
// search for the entity by EntityItemID
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
// search for the entity by EntityItemID
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
if (existingEntity && packetType == PacketTypeEntityEdit) {
// if the EntityItem exists, then update it
if (existingEntity) {
if (wantEditLogging()) {
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
qCDebug(entities) << " properties:" << properties;
}
updateEntity(entityItemID, properties, senderNode);
existingEntity->markAsChangedOnServer();
} else {
qCDebug(entities) << "User attempted to edit an unknown entity. ID:" << entityItemID;
if (wantEditLogging()) {
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
qCDebug(entities) << " properties:" << properties;
}
} else {
updateEntity(entityItemID, properties, senderNode);
existingEntity->markAsChangedOnServer();
} else if (packetType == PacketTypeEntityAdd) {
if (senderNode->getCanRez()) {
// this is a new entity... assign a new entityID
entityItemID = assignEntityID(entityItemID);
if (wantEditLogging()) {
qCDebug(entities) << "User [" << senderNode->getUUID() << "] adding entity.";
qCDebug(entities) << " properties:" << properties;
}
properties.setCreated(properties.getLastEdited());
EntityItem* newEntity = addEntity(entityItemID, properties);
if (newEntity) {
newEntity->markAsChangedOnServer();
@ -720,8 +600,11 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
}
} else {
qCDebug(entities) << "User without 'rez rights' [" << senderNode->getUUID() << "] attempted to add an entity.";
qCDebug(entities) << "User without 'rez rights' [" << senderNode->getUUID()
<< "] attempted to add an entity.";
}
} else {
qCDebug(entities) << "Add or Edit failed." << packetType << existingEntity;
}
}
break;
@ -1026,66 +909,15 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ {
// TODO: do we need to make this thread safe? Or is it acceptable as is
EntityTreeElement* element = _entityToElementMap.value(entityItemID);
if (!element && entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN){
// check the creator token version too...
EntityItemID creatorTokenOnly;
creatorTokenOnly.id = UNKNOWN_ENTITY_ID;
creatorTokenOnly.creatorTokenID = entityItemID.creatorTokenID;
creatorTokenOnly.isKnownID = false;
element = _entityToElementMap.value(creatorTokenOnly);
}
// If we still didn't find the entity, but the ID was in our changed entityIDs, search for the new ID version
if (!element && _changedEntityIDs.contains(entityItemID)) {
element = getContainingElement(_changedEntityIDs[entityItemID]);
}
return element;
}
// TODO: do we need to make this thread safe? Or is it acceptable as is
void EntityTree::resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
if (entityItemID.id == UNKNOWN_ENTITY_ID) {
//assert(entityItemID.id != UNKNOWN_ENTITY_ID);
qCDebug(entities) << "UNEXPECTED! resetContainingElement() called with UNKNOWN_ENTITY_ID. entityItemID:" << entityItemID;
return;
}
if (entityItemID.creatorTokenID == UNKNOWN_ENTITY_TOKEN) {
//assert(entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN);
qCDebug(entities) << "UNEXPECTED! resetContainingElement() called with UNKNOWN_ENTITY_TOKEN. entityItemID:" << entityItemID;
return;
}
if (!element) {
//assert(element);
qCDebug(entities) << "UNEXPECTED! resetContainingElement() called with NULL element. entityItemID:" << entityItemID;
return;
}
// remove the old version with the creatorTokenID
EntityItemID creatorTokenVersion;
creatorTokenVersion.id = UNKNOWN_ENTITY_ID;
creatorTokenVersion.isKnownID = false;
creatorTokenVersion.creatorTokenID = entityItemID.creatorTokenID;
_entityToElementMap.remove(creatorTokenVersion);
// set the new version with both creator token and real ID
_entityToElementMap[entityItemID] = element;
}
void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
// TODO: do we need to make this thread safe? Or is it acceptable as is
// If we're a sever side tree, we always remove the creator tokens from our map items
EntityItemID storedEntityItemID = entityItemID;
if (getIsServer()) {
storedEntityItemID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
}
if (element) {
_entityToElementMap[storedEntityItemID] = element;
_entityToElementMap[entityItemID] = element;
} else {
_entityToElementMap.remove(storedEntityItemID);
_entityToElementMap.remove(entityItemID);
}
}
@ -1174,14 +1006,14 @@ bool EntityTree::sendEntitiesOperation(OctreeElement* element, void* extraData)
const QList<EntityItem*>& entities = entityTreeElement->getEntities();
for (int i = 0; i < entities.size(); i++) {
EntityItemID newID(NEW_ENTITY, EntityItemID::getNextCreatorTokenID(), false);
EntityItemID newID(QUuid::createUuid());
args->newEntityIDs->append(newID);
EntityItemProperties properties = entities[i]->getProperties();
properties.setPosition(properties.getPosition() + args->root);
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
// queue the packet to send to the server
args->packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, newID, properties);
args->packetSender->queueEditEntityMessage(PacketTypeEntityAdd, newID, properties);
// also update the local tree instantly (note: this is not our tree, but an alternate tree)
if (args->localTree) {
@ -1226,7 +1058,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
EntityItem* entity = addEntity(entityItemID, properties);
if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << entity->getType();
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
}
}

View file

@ -135,7 +135,6 @@ public:
int processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
int processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
void handleAddEntityResponse(const QByteArray& packet);
EntityItemFBXService* getFBXService() const { return _fbxService; }
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
@ -148,7 +147,6 @@ public:
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/;
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
void resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
void debugDumpMap();
virtual void dumpTree();
virtual void pruneTree();
@ -198,7 +196,6 @@ private:
EntityItemFBXService* _fbxService;
QHash<EntityItemID, EntityTreeElement*> _entityToElementMap;
QHash<EntityItemID, EntityItemID> _changedEntityIDs;
EntitySimulation* _simulation;

View file

@ -567,19 +567,6 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
return false;
}
void EntityTreeElement::updateEntityItemID(const EntityItemID& creatorTokenEntityID, const EntityItemID& knownIDEntityID) {
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
EntityItem* thisEntity = (*_entityItems)[i];
EntityItemID thisEntityID = thisEntity->getEntityItemID();
if (thisEntityID == creatorTokenEntityID) {
thisEntity->setID(knownIDEntityID.id);
}
}
}
const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const {
const EntityItem* closestEntity = NULL;
float closestEntityDistance = FLT_MAX;

View file

@ -151,9 +151,6 @@ public:
bool updateEntity(const EntityItem& entity);
void addEntityItem(EntityItem* entity);
void updateEntityItemID(const EntityItemID& creatorTokenEntityID, const EntityItemID& knownIDEntityID);
const EntityItem* getClosestEntity(glm::vec3 position) const;
/// finds all entities that touch a sphere

View file

@ -70,9 +70,10 @@ PacketVersion versionForPacketType(PacketType packetType) {
return 1;
case PacketTypeStopNode:
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityAdd:
case PacketTypeEntityEdit:
case PacketTypeEntityData:
return VERSION_ENTITIES_HAVE_FRICTION;
return VERSION_NO_ENTITY_ID_SWAP;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:
@ -117,9 +118,7 @@ QString nameForPacketType(PacketType packetType) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeNodeJsonStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityQuery);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddOrEdit);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
@ -129,6 +128,8 @@ QString nameForPacketType(PacketType packetType) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
default:
return QString("Type: ") + QString::number((int)packetType);
}

View file

@ -68,9 +68,9 @@ enum PacketType {
PacketTypeNodeJsonStats,
PacketTypeEntityQuery, // 40
PacketTypeEntityData,
PacketTypeEntityAddOrEdit,
PacketTypeEntityAdd,
PacketTypeEntityErase,
PacketTypeEntityAddResponse,
PacketTypeEntityEdit,
PacketTypeOctreeDataNack, // 45
PacketTypeStopNode,
PacketTypeAudioEnvironment,
@ -178,5 +178,6 @@ const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23;
const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24;
const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
#endif // hifi_PacketHeaders_h

View file

@ -334,7 +334,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
assert(_entity);
assert(_entity->isKnownID());
bool active = _body->isActive();
if (!active) {
@ -434,7 +433,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()...";
#endif
entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties);
entityPacketSender->queueEditEntityMessage(PacketTypeEntityEdit, id, properties);
_entity->setLastBroadcast(usecTimestampNow());
} else {
#ifdef WANT_DEBUG

View file

@ -196,7 +196,7 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
EntityItem* entity = entityState->getEntity();
if (entity) {
if (entity->isKnownID() && entityState->isCandidateForOwnership(sessionID)) {
if (entityState->isCandidateForOwnership(sessionID)) {
_outgoingChanges.insert(entityState);
}
_entitiesToSort.insert(entityState->getEntity());

View file

@ -321,7 +321,8 @@ void ScriptEngine::init() {
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<EntityItemID> >(this);
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this);
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);
qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);

View file

@ -200,11 +200,18 @@ void collisionFromScriptValue(const QScriptValue &object, Collision& collision)
}
QScriptValue quuidToScriptValue(QScriptEngine* engine, const QUuid& uuid) {
if (uuid.isNull()) {
return QScriptValue::NullValue;
}
QScriptValue obj(uuid.toString());
return obj;
}
void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid) {
if (object.isNull()) {
uuid = QUuid();
return;
}
QString uuidAsString = object.toVariant().toString();
QUuid fromString(uuidAsString);
uuid = fromString;

View file

@ -42,7 +42,6 @@ void EntityTests::entityTreeTests(bool verbose) {
EntityTree tree;
QUuid id = QUuid::createUuid();
EntityItemID entityID(id);
entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs
EntityItemProperties properties;
float oneMeter = 1.0f;
float halfOfDomain = TREE_SCALE * 0.5f;
@ -90,8 +89,6 @@ void EntityTests::entityTreeTests(bool verbose) {
}
}
entityID.isKnownID = true; // this is a temporary workaround to allow local tree entities to be added with known IDs
{
testsTaken++;
QString testName = "change position of entity in tree";
@ -253,7 +250,6 @@ void EntityTests::entityTreeTests(bool verbose) {
for (int i = 0; i < TEST_ITERATIONS; i++) {
QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
EntityItemID entityID(id);
entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs
float randomX = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
float randomY = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
@ -357,7 +353,6 @@ void EntityTests::entityTreeTests(bool verbose) {
for (int i = 0; i < TEST_ITERATIONS; i++) {
QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
EntityItemID entityID(id);
entityID.isKnownID = true; // this is a temporary workaround to allow local tree entities to be added with known IDs
if (extraVerbose) {
qDebug() << "before:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();