// // coordinatorAC.js // // Created by Thijs Wenker on 4/14/17 // Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // //debugger; var randFloat = function(low, high) { return low + Math.random() * (high - low); }; var VISUALIZATION = false; var COORDINATOR_CHANNEL = 'COORDINATOR-AC'; var ACTOR_CHANNEL_PREFIX = 'ACTOR-PLAYBACK-AC_'; var AVATARS_ARRAY = [ "http://cdn.highfidelity.com/chris/production/morph/1/1.fst", "http://cdn.highfidelity.com/chris/production/morph/2/2.fst", "http://cdn.highfidelity.com/chris/production/morph/3/3.fst", "http://cdn.highfidelity.com/chris/production/morph/4/4.fst", "http://cdn.highfidelity.com/chris/production/morph/5/5.fst", "http://cdn.highfidelity.com/chris/production/morph/6/6.fst", "http://cdn.highfidelity.com/chris/production/morph/7/7.fst", "http://cdn.highfidelity.com/chris/production/morph/8/8.fst", "http://cdn.highfidelity.com/chris/production/morph/9/9.fst", "http://cdn.highfidelity.com/chris/production/morph/10/10.fst", "http://cdn.highfidelity.com/chris/production/morph/11/11.fst", "http://cdn.highfidelity.com/chris/production/morph/12/12.fst", "http://cdn.highfidelity.com/chris/production/morph/13/13.fst", "http://cdn.highfidelity.com/chris/production/morph/14/14.fst", "http://cdn.highfidelity.com/chris/production/morph/15/15.fst", "http://cdn.highfidelity.com/chris/production/morph/16/16.fst", "http://cdn.highfidelity.com/chris/production/morph/17/17.fst", "http://cdn.highfidelity.com/chris/production/morph/18/18.fst", "http://cdn.highfidelity.com/chris/production/morph/19/19.fst", "http://cdn.highfidelity.com/chris/production/morph/20/20.fst", "http://cdn.highfidelity.com/chris/production/morph/21/21.fst", "http://cdn.highfidelity.com/chris/production/morph/22/22.fst", "http://cdn.highfidelity.com/chris/production/morph/23/23.fst", "http://cdn.highfidelity.com/chris/production/morph/24/24.fst", "http://cdn.highfidelity.com/chris/production/morph/25/25.fst", "http://cdn.highfidelity.com/chris/production/morph/26/26.fst", "http://cdn.highfidelity.com/chris/production/morph/27/27.fst", "http://cdn.highfidelity.com/chris/production/morph/28/28.fst", "http://cdn.highfidelity.com/chris/production/morph/29/29.fst", "http://cdn.highfidelity.com/chris/production/morph/30/30.fst", "http://cdn.highfidelity.com/chris/production/morph/31/31.fst", "http://cdn.highfidelity.com/chris/production/morph/32/32.fst", "http://cdn.highfidelity.com/chris/production/morph/33/33.fst", "http://cdn.highfidelity.com/chris/production/morph/34/34.fst", "http://cdn.highfidelity.com/chris/production/morph/35/35.fst", "http://cdn.highfidelity.com/chris/production/morph/36/36.fst", "http://cdn.highfidelity.com/chris/production/morph/37/37.fst", "http://cdn.highfidelity.com/chris/production/morph/38/38.fst", "http://cdn.highfidelity.com/chris/production/morph/39/39.fst", "http://cdn.highfidelity.com/chris/production/morph/40/40.fst", "http://cdn.highfidelity.com/chris/production/morph/41/41.fst", "http://cdn.highfidelity.com/chris/production/morph/42/42.fst", "http://cdn.highfidelity.com/chris/production/morph/43/43.fst", "http://cdn.highfidelity.com/chris/production/morph/44/44.fst", "http://cdn.highfidelity.com/chris/production/morph/45/45.fst", "http://cdn.highfidelity.com/chris/production/morph/46/46.fst", "http://cdn.highfidelity.com/chris/production/morph/47/47.fst", "http://cdn.highfidelity.com/chris/production/morph/48/48.fst", "http://cdn.highfidelity.com/chris/production/morph/49/49.fst", "http://cdn.highfidelity.com/chris/production/morph/50/50.fst", "http://cdn.highfidelity.com/chris/production/morph/51/51.fst", "http://cdn.highfidelity.com/chris/production/morph/52/52.fst", "http://cdn.highfidelity.com/chris/production/morph/53/53.fst", "http://cdn.highfidelity.com/chris/production/morph/54/54.fst", "http://cdn.highfidelity.com/chris/production/morph/55/55.fst", "http://cdn.highfidelity.com/chris/production/morph/56/56.fst", "http://cdn.highfidelity.com/chris/production/morph/57/57.fst", "http://cdn.highfidelity.com/chris/production/morph/58/58.fst", "http://cdn.highfidelity.com/chris/production/morph/59/59.fst", "http://cdn.highfidelity.com/chris/production/morph/60/60.fst", "http://cdn.highfidelity.com/chris/production/morph/61/61.fst", "http://cdn.highfidelity.com/chris/production/morph/62/62.fst", "http://cdn.highfidelity.com/chris/production/morph/63/63.fst", "http://cdn.highfidelity.com/chris/production/morph/64/64.fst", "http://cdn.highfidelity.com/chris/production/morph/65/65.fst", "http://cdn.highfidelity.com/chris/production/morph/66/66.fst", "http://cdn.highfidelity.com/chris/production/morph/67/67.fst", "http://cdn.highfidelity.com/chris/production/morph/68/68.fst", "http://cdn.highfidelity.com/chris/production/morph/69/69.fst", "http://cdn.highfidelity.com/chris/production/morph/70/70.fst", "http://cdn.highfidelity.com/chris/production/morph/71/71.fst", "http://cdn.highfidelity.com/chris/production/morph/72/72.fst", "http://cdn.highfidelity.com/chris/production/morph/73/73.fst", "http://cdn.highfidelity.com/chris/production/morph/74/74.fst", "http://cdn.highfidelity.com/chris/production/morph/75/75.fst", "http://cdn.highfidelity.com/chris/production/morph/76/76.fst", "http://cdn.highfidelity.com/chris/production/morph/77/77.fst", "http://cdn.highfidelity.com/chris/production/morph/78/78.fst", "http://cdn.highfidelity.com/chris/production/morph/79/79.fst", "http://cdn.highfidelity.com/chris/production/morph/80/80.fst", "http://cdn.highfidelity.com/chris/production/morph/81/81.fst", "http://cdn.highfidelity.com/chris/production/morph/82/82.fst", "http://cdn.highfidelity.com/chris/production/morph/83/83.fst", "http://cdn.highfidelity.com/chris/production/morph/84/84.fst", "http://cdn.highfidelity.com/chris/production/morph/85/85.fst", "http://cdn.highfidelity.com/chris/production/morph/86/86.fst", "http://cdn.highfidelity.com/chris/production/morph/87/87.fst", "http://cdn.highfidelity.com/chris/production/morph/88/88.fst", "http://cdn.highfidelity.com/chris/production/morph/89/89.fst", "http://cdn.highfidelity.com/chris/production/morph/90/90.fst", "http://cdn.highfidelity.com/chris/production/morph/91/91.fst", "http://cdn.highfidelity.com/chris/production/morph/92/92.fst", "http://cdn.highfidelity.com/chris/production/morph/93/93.fst", "http://cdn.highfidelity.com/chris/production/morph/94/94.fst", "http://cdn.highfidelity.com/chris/production/morph/95/95.fst", "http://cdn.highfidelity.com/chris/production/morph/96/96.fst", "http://cdn.highfidelity.com/chris/production/morph/97/97.fst", "http://cdn.highfidelity.com/chris/production/morph/98/98.fst", "http://cdn.highfidelity.com/chris/production/morph/99/99.fst", "http://cdn.highfidelity.com/chris/production/morph/100/100.fst", "http://cdn.highfidelity.com/chris/production/morph/101/101.fst", "http://cdn.highfidelity.com/chris/production/morph/102/102.fst", "http://cdn.highfidelity.com/chris/production/morph/103/103.fst", "http://cdn.highfidelity.com/chris/production/morph/104/104.fst" ]; var RECORDINGS_ARRAY = [ "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/peanuts.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/arya_heyChris.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/cal_alrightCool.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/carmen_excuseMe.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/fausto_someGoodSeats.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/halima_thatdBeFine.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_sargon_duckiesAndBunnies.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_bianca_smileInTheMorning.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_kobe_adversityHasStrengthenedMe.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_raffaello_tryTheCottonCandy.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_rasta_noLinesInNature.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_mcGee_strawberries.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_purple_manNeedsColorToLive.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_roia_differentOpinions.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_annie_newDayNewStrength.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_halima_aCalmMind.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_isobel_warIsPeace.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_carmen_humanRelationship.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_barbarian_grunting.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_arya_iAmALoveBoat.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_skeleton_buenoEstante.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_robot_scanningLifeForms.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_priscille_iCantDecide.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_beingOfLight_beingAbeing.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/artemis_wheresBill.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/chloe_imOkay.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/haj_overhere.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/halima_dietCoke.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/maery_hiChrisOverHere.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/matthew_cool.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/matthew_niceplace.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/mcgee_takePeanuts.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/pris_isntSoBad.hfr", "http://hifi-content.s3.amazonaws.com/caitlyn/dev/npc/npc_theaterTakes/raff_venue.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/usher3.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/usher2.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/usher1.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/claude.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting10.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting9.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting8.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting7.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting6.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting5.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting4.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting3.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting2.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting1.hfr" ]; // http://stackoverflow.com/a/2450976 function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } Messages.messageReceived.connect(function (channel, message, senderID) { if (channel === COORDINATOR_CHANNEL) { if (message === 'request') { if (reservedActors.length === 0) { print('No actor spaces available.'); return; } var reservedActor = reservedActors.pop(); Messages.sendMessage(ACTOR_CHANNEL_PREFIX + senderID, JSON.stringify({ position: reservedActor.position, avatarURL: reservedActor.avatarURL, recordingURL: reservedActor.recordingURL, displayName: reservedActor.displayName })); } } }); Script.setTimeout(function() { Messages.subscribe(COORDINATOR_CHANNEL); Messages.sendMessage(COORDINATOR_CHANNEL, 'init'); }, 300); var COMFORTABLE_AVATAR_DISTANCE = 0.6; // location comments are given while looking from stage towards the audience var AREAS_ARRAY = [ // front level { minX: 97.0, maxX: 103.0, y: -0.6, minZ: 37, maxZ: 41 , rows: 4, fill: 0.6 }, // level 1 left { minX: 92.7, maxX: 98.9, y: -0.3, minZ: 43, maxZ: 43 }, // level 1 right { minX: 100.3, maxX: 106.6, y: -0.3, minZ: 43, maxZ: 43 }, // level 2 left { minX: 92.7, maxX: 98.9, y: 0.3, minZ: 45, maxZ: 45 }, // level 2 right { minX: 100.3, maxX: 106.6, y: 0.3, minZ: 45, maxZ: 45 }, // level 3 left { minX: 92.7, maxX: 98.9, y: 1 , minZ: 47, maxZ: 47 }, // level 3 right { minX: 100.3, maxX: 106.6, y: 1 , minZ: 47, maxZ: 47 }, // top level { minX: 92.7, maxX: 106.6, y: 1.7, minZ: 51.9, maxZ: 51.9} ]; var DUPLICATE_PREVENTION_MODES = { NONE: 0, RANDOM_LISTS: 1, PREVENT_SAME_NEIGHBOR: 2 }; var reservedActors = []; var totalSpaces = 0; var minAvatarFill = 0.8; // 80% var maxRand = 0; var createSpaceManager = function(areas, expectedAvatars, duplicatePreventionMode) { var _this, _areas, _areaDetails, _expectedAvatars, _duplicatePreventionMode; function SpaceManager(areas) { _this = this; _areas = areas; _expectedAvatars = expectedAvatars; _duplicatePreventionMode = duplicatePreventionMode; _areaDetails = []; _this.initAreaDetails(); _this.reserveActors(); } SpaceManager.prototype = { initAreaDetails: function() { _areaDetails = []; _areas.forEach(function(area) { var randomNum = Math.random(); maxRand += randomNum; var width = area.maxX - area.minX; var height = area.maxZ - area.minZ; var columns = (Math.floor(width / COMFORTABLE_AVATAR_DISTANCE) + 1); var rows = (Math.floor(height / COMFORTABLE_AVATAR_DISTANCE) + 1); var spaces = columns * rows; totalSpaces += spaces; _areaDetails.push({ area: area, spaces: spaces, reservedActorIndexes: [], spacesPreferred: -1, width: width, height: height, columns: columns, rows: rows, random: randomNum }); }); var averageFactor = _expectedAvatars / totalSpaces; print('avg fact' + averageFactor); var spacesOccupied = 0; _areaDetails.forEach(function(details) { var percentage = details.random / maxRand; var fillPercentage = details.area.fill !== undefined ? details.area.fill : minAvatarFill + (_areaDetails.length * percentage * ((1.0 - minAvatarFill) * 2.0)); print('fp: ' + percentage + ' ' + fillPercentage); details.spacesPreferred = Math.ceil(fillPercentage * details.spaces) * averageFactor; spacesOccupied += details.spacesPreferred; }); print("Spaces occupied " + spacesOccupied); if (totalSpaces < _expectedAvatars) { print('Please add some more area for your actors.'); } }, getAreas: function() { return _areaDetails; }, reserveActors: function() { reservedActors = []; var randomRecordingURLS = shuffle(RECORDINGS_ARRAY.slice()); var randomAvatarModelURLS = shuffle(AVATARS_ARRAY.slice()); _areaDetails.forEach(function(details) { var rows = details.area.rows !== undefined ? details.area.rows : details.rows; var columnStep = (details.width / details.spacesPreferred) * rows; var rowStep = Math.floor(details.height / rows); for (var i = 0; i < details.spacesPreferred; i++) { if (randomRecordingURLS.length === 0) { randomRecordingURLS = shuffle(RECORDINGS_ARRAY.slice()); } if (randomAvatarModelURLS.length === 0) { randomAvatarModelURLS = shuffle(AVATARS_ARRAY.slice()); } reservedActors.push({ position: { x: details.area.minX + ((columnStep * (i / rows))) + (columnStep * 0.5) + (Math.random() * columnStep * 0.5), y: details.area.y, z: details.area.minZ + ((rowStep * (i % rows))) + (rowStep * 0.5) + (Math.random() * rowStep * 0.5) //Math.random() * details.height }, displayName: 'Crowd NPC (spot ' + (reservedActors.length + 1) + ')', recordingURL: randomRecordingURLS.pop(), avatarURL: randomAvatarModelURLS.pop(), sessionUUID: null }); } }); reservedActors = shuffle(reservedActors); } }; return new SpaceManager(areas, expectedAvatars, duplicatePreventionMode); }; var EXPECTED_NUMBER_OF_AVATARS = 100; var spaceManager = createSpaceManager(AREAS_ARRAY, EXPECTED_NUMBER_OF_AVATARS, DUPLICATE_PREVENTION_MODES.RANDOM_LISTS); if (this.Agent !== undefined) { Agent.isAvatar = true; Avatar.position = {x: 0, y: 0, z: 0}; Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; Avatar.skeletonModelURL = 'http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst'; } if (VISUALIZATION) { // Visualization var FLOOR_OFFSET = {y: -0.6}; var VISUALIZATION_LIFETIME = 360; // seconds var floorEntities = []; var actorEntities = []; spaceManager.getAreas().forEach(function (details) { var dimensionX = details.width; var dimensionZ = details.height; floorEntities.push(Entities.addEntity({ type: 'Box', dimensions: { x: Math.max(dimensionX, COMFORTABLE_AVATAR_DISTANCE), y: 0.05, z: Math.max(dimensionZ, COMFORTABLE_AVATAR_DISTANCE) }, position: Vec3.sum({ x: details.area.minX + (dimensionX / 2), y: details.area.y, z: details.area.minZ + (dimensionZ / 2) }, FLOOR_OFFSET), lifetime: VISUALIZATION_LIFETIME })); }); reservedActors = shuffle(reservedActors); for (var i = 0; i < EXPECTED_NUMBER_OF_AVATARS && i < reservedActors.length; i++) { actorEntities.push(Entities.addEntity({ type: 'Model', position: reservedActors[i].position, modelURL: reservedActors[i].avatarURL, rotation: Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0), lifetime: VISUALIZATION_LIFETIME })); } Script.scriptEnding.connect(function () { floorEntities.forEach(function (floor) { Entities.deleteEntity(floor); }); actorEntities.forEach(function (actor) { Entities.deleteEntity(actor); }); }); }