From f5a04026fc8591c53cf9c5357bef5512c6f47b51 Mon Sep 17 00:00:00 2001 From: Dale Glass <dale@daleglass.net> Date: Sun, 13 Feb 2022 23:27:08 +0100 Subject: [PATCH] More files --- hifi-content/hifi-worklist-logo.jpg | 3 + hifi-content/high-fidelity-og.jpg | 3 + hifi-content/high-fidelity-og_load-test.jpg | 3 + .../zaru-content-custom-scripts.zip | 1 + .../resources/avatar/animations/idle.fbx | 1 + .../resources/avatar/animations/walk_fwd.fbx | 3 + .../meshes/being_of_light/being_of_light.fbx | 1 + .../BaseMesh_BeingofLight_DiffuseMap.png | 1 + .../BaseMesh_BeingofLight_EmissiveMap.png | 1 + .../BaseMesh_BeingofLight_NormalMap.png | 1 + .../resources/meshes/defaultAvatar_full.fst | 1 + hifi-content/howard/scripts/dev-welcome.js | 64 ++++ .../scripts/tests/performance/crowd-agent.js | 166 +++++++++ .../scripts/tests/performance/domain-check.js | 345 ++++++++++++++++++ .../tests/performance/screamingAvatarAC.js | 39 ++ .../scripts/tests/performance/summon.js | 157 ++++++++ hifi-content/howard/sounds/hello.wav | 3 + hifi-content/howard/sounds/piano1.wav | 3 + .../howard/zaru-content-custom-scripts.zip | 3 + .../howard/zaru-content-default-scripts.zip | 3 + .../Cartoony_Computer/CCTV_image-redigert.jpg | 3 + .../Cartoony_Computer/Cartoony_Computer.FBX | 3 + .../Cartoony_Computer/Cartoony_Computer.max | 3 + .../Cartoony_Computer/Cartoony_Computer.mtl | 84 +++++ .../Cartoony_Computer/Cartoony_Computer.obj | 3 + .../Cartoony_Computer[max2010].max | 3 + hifi-content/howell/Prototypes/GOT/GOT.png | 3 + .../GOT/drogon finished with base2.obj | 3 + .../howell/Prototypes/GOT/drogon-statue.fbx | 3 + .../Prototypes/Idle_app/Hanging Idle.fbx | 3 + .../howell/Prototypes/Idle_app/Happy.fbx | 3 + .../Prototypes/Idle_app/Male Laying Pose.fbx | 3 + .../howell/Prototypes/Idle_app/Ninja Idle.fbx | 3 + .../howell/Prototypes/Idle_app/Push Up.fbx | 3 + .../howell/Prototypes/Idle_app/mat_laying.fbx | 3 + .../howell/Prototypes/JAT_test/JATScritp.js | 344 +++++++++++++++++ .../howell/Prototypes/JAT_test/config.json | 27 ++ .../howell/Prototypes/andy_bot_bingos.js | 125 +++++++ hifi-content/howell/Prototypes/andy_bots.js | 125 +++++++ .../Prototypes/andy_bots_futvrelands.js | 203 +++++++++++ hifi-content/howell/Prototypes/best_game.jpg | 3 + .../assignmentClientManager_andy_test.js | 247 +++++++++++++ hifi-content/howell/Prototypes/bouncer.js | 270 ++++++++++++++ hifi-content/howell/Prototypes/crabble.png | 3 + .../howell/Prototypes/dog_skull/dogskull.mtl | 14 + .../howell/Prototypes/dog_skull/dogskull.obj | 3 + .../Prototypes/dog_skull/dogskull_u1_v1.jpg | 3 + hifi-content/howell/Prototypes/glasses.jpg | 3 + .../howell/Prototypes/jat_test2/JATScritp.js | 1 + .../howell/Prototypes/jat_test2/config.json | 1 + .../howell/Prototypes/jat_test3/JATScritp.js | 1 + .../howell/Prototypes/jat_test3/config.json | 27 ++ .../howell/Prototypes/neon_snowflake.jpg | 3 + hifi-content/howell/Prototypes/neonturkey.jpg | 3 + hifi-content/howell/Prototypes/pants.JPG | 3 + hifi-content/howell/Prototypes/pumpkins.jpg | 3 + hifi-content/howell/Prototypes/satdium.fbx | 3 + hifi-content/howell/Prototypes/shirt.jpg | 3 + hifi-content/howell/Prototypes/snowflake.PNG | 3 + hifi-content/howell/Prototypes/space.jpg | 3 + hifi-content/howell/Prototypes/space2.jpg | 3 + .../howell/Prototypes/team_directory.PNG | 3 + hifi-content/howell/Prototypes/turkeybleh.png | 3 + .../howell/Prototypes/ugly_sweater.jpg | 3 + .../Prototypes/wheel_of_current_events.png | 3 + hifi-content/howell/bots/AVATAR_TEST1.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST10.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST11.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST12.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST13.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST14.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST15.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST16.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST17.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST18.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST19.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST2.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST20.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST3.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST4.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST5.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST6.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST7.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST8.hfr | 3 + hifi-content/howell/bots/AVATAR_TEST9.hfr | 3 + hifi-content/howell/bots/_AVATAR_TEST5.hfr | 1 + hifi-content/howell/bots_new/AVATAR_TEST1.hfr | 3 + .../howell/usertesting/can_you_see_me.txt | 1 + .../huffman/avatars/tubeboy/tubeboy.fst | 131 +++++++ .../avatars/tubeboy/tubeboy/tubeboy.fbx | 3 + .../huffman/ctf/Portal-Red-Blue.svo.json | 175 +++++++++ hifi-content/huffman/ctf/README.md | 24 ++ hifi-content/huffman/ctf/ballClientEntity.js | 67 ++++ hifi-content/huffman/ctf/firework.js | 147 ++++++++ hifi-content/huffman/ctf/goalClientEntity.js | 50 +++ .../huffman/ctf/gunSpawnerClientEntity.js | 124 +++++++ hifi-content/huffman/ctf/models/portalgun.fbx | 1 + .../huffman/ctf/models/portalgun_blue.fbx | 1 + .../huffman/ctf/models/portalgun_collider.obj | 1 + .../huffman/ctf/models/portalgun_red.fbx | 1 + .../huffman/ctf/origina_portal_gun.js | 210 +++++++++++ .../huffman/ctf/portalBulletClientEntity.js | 47 +++ .../huffman/ctf/portalGunClientEntity.js | 222 +++++++++++ hifi-content/huffman/ctf/portalgun.json | 81 ++++ hifi-content/huffman/ctf/sounds/gunFire.wav | 3 + .../huffman/ctf/sounds/pong_sound.wav | 3 + hifi-content/huffman/ctf/sounds/teleport.raw | Bin 0 -> 106592 bytes hifi-content/huffman/ctf/spawnPortalGun.js | 99 +++++ hifi-content/huffman/ctf/utils.js | 93 +++++ hifi-content/huffman/essTest.js | 9 + 110 files changed, 3924 insertions(+) create mode 100644 hifi-content/hifi-worklist-logo.jpg create mode 100644 hifi-content/high-fidelity-og.jpg create mode 100644 hifi-content/high-fidelity-og_load-test.jpg create mode 120000 hifi-content/howard/production/zaru-content-custom-scripts.zip create mode 120000 hifi-content/howard/resources/avatar/animations/idle.fbx create mode 100644 hifi-content/howard/resources/avatar/animations/walk_fwd.fbx create mode 120000 hifi-content/howard/resources/meshes/being_of_light/being_of_light.fbx create mode 120000 hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_DiffuseMap.png create mode 120000 hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_EmissiveMap.png create mode 120000 hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_NormalMap.png create mode 120000 hifi-content/howard/resources/meshes/defaultAvatar_full.fst create mode 100644 hifi-content/howard/scripts/dev-welcome.js create mode 100644 hifi-content/howard/scripts/tests/performance/crowd-agent.js create mode 100644 hifi-content/howard/scripts/tests/performance/domain-check.js create mode 100644 hifi-content/howard/scripts/tests/performance/screamingAvatarAC.js create mode 100644 hifi-content/howard/scripts/tests/performance/summon.js create mode 100644 hifi-content/howard/sounds/hello.wav create mode 100644 hifi-content/howard/sounds/piano1.wav create mode 100644 hifi-content/howard/zaru-content-custom-scripts.zip create mode 100644 hifi-content/howard/zaru-content-default-scripts.zip create mode 100644 hifi-content/howell/Prototypes/Cartoony_Computer/CCTV_image-redigert.jpg create mode 100644 hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.FBX create mode 100644 hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.max create mode 100644 hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.mtl create mode 100644 hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.obj create mode 100644 hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer[max2010].max create mode 100644 hifi-content/howell/Prototypes/GOT/GOT.png create mode 100644 hifi-content/howell/Prototypes/GOT/drogon finished with base2.obj create mode 100644 hifi-content/howell/Prototypes/GOT/drogon-statue.fbx create mode 100644 hifi-content/howell/Prototypes/Idle_app/Hanging Idle.fbx create mode 100644 hifi-content/howell/Prototypes/Idle_app/Happy.fbx create mode 100644 hifi-content/howell/Prototypes/Idle_app/Male Laying Pose.fbx create mode 100644 hifi-content/howell/Prototypes/Idle_app/Ninja Idle.fbx create mode 100644 hifi-content/howell/Prototypes/Idle_app/Push Up.fbx create mode 100644 hifi-content/howell/Prototypes/Idle_app/mat_laying.fbx create mode 100644 hifi-content/howell/Prototypes/JAT_test/JATScritp.js create mode 100644 hifi-content/howell/Prototypes/JAT_test/config.json create mode 100644 hifi-content/howell/Prototypes/andy_bot_bingos.js create mode 100644 hifi-content/howell/Prototypes/andy_bots.js create mode 100644 hifi-content/howell/Prototypes/andy_bots_futvrelands.js create mode 100644 hifi-content/howell/Prototypes/best_game.jpg create mode 100644 hifi-content/howell/Prototypes/bot_player_content_v4/assignmentClientManager_andy_test.js create mode 100644 hifi-content/howell/Prototypes/bouncer.js create mode 100644 hifi-content/howell/Prototypes/crabble.png create mode 100644 hifi-content/howell/Prototypes/dog_skull/dogskull.mtl create mode 100644 hifi-content/howell/Prototypes/dog_skull/dogskull.obj create mode 100644 hifi-content/howell/Prototypes/dog_skull/dogskull_u1_v1.jpg create mode 100644 hifi-content/howell/Prototypes/glasses.jpg create mode 120000 hifi-content/howell/Prototypes/jat_test2/JATScritp.js create mode 120000 hifi-content/howell/Prototypes/jat_test2/config.json create mode 120000 hifi-content/howell/Prototypes/jat_test3/JATScritp.js create mode 100644 hifi-content/howell/Prototypes/jat_test3/config.json create mode 100644 hifi-content/howell/Prototypes/neon_snowflake.jpg create mode 100644 hifi-content/howell/Prototypes/neonturkey.jpg create mode 100644 hifi-content/howell/Prototypes/pants.JPG create mode 100644 hifi-content/howell/Prototypes/pumpkins.jpg create mode 100644 hifi-content/howell/Prototypes/satdium.fbx create mode 100644 hifi-content/howell/Prototypes/shirt.jpg create mode 100644 hifi-content/howell/Prototypes/snowflake.PNG create mode 100644 hifi-content/howell/Prototypes/space.jpg create mode 100644 hifi-content/howell/Prototypes/space2.jpg create mode 100644 hifi-content/howell/Prototypes/team_directory.PNG create mode 100644 hifi-content/howell/Prototypes/turkeybleh.png create mode 100644 hifi-content/howell/Prototypes/ugly_sweater.jpg create mode 100644 hifi-content/howell/Prototypes/wheel_of_current_events.png create mode 100644 hifi-content/howell/bots/AVATAR_TEST1.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST10.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST11.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST12.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST13.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST14.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST15.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST16.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST17.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST18.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST19.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST2.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST20.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST3.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST4.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST5.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST6.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST7.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST8.hfr create mode 100644 hifi-content/howell/bots/AVATAR_TEST9.hfr create mode 120000 hifi-content/howell/bots/_AVATAR_TEST5.hfr create mode 100644 hifi-content/howell/bots_new/AVATAR_TEST1.hfr create mode 100644 hifi-content/howell/usertesting/can_you_see_me.txt create mode 100644 hifi-content/huffman/avatars/tubeboy/tubeboy.fst create mode 100644 hifi-content/huffman/avatars/tubeboy/tubeboy/tubeboy.fbx create mode 100644 hifi-content/huffman/ctf/Portal-Red-Blue.svo.json create mode 100644 hifi-content/huffman/ctf/README.md create mode 100644 hifi-content/huffman/ctf/ballClientEntity.js create mode 100644 hifi-content/huffman/ctf/firework.js create mode 100644 hifi-content/huffman/ctf/goalClientEntity.js create mode 100644 hifi-content/huffman/ctf/gunSpawnerClientEntity.js create mode 120000 hifi-content/huffman/ctf/models/portalgun.fbx create mode 120000 hifi-content/huffman/ctf/models/portalgun_blue.fbx create mode 120000 hifi-content/huffman/ctf/models/portalgun_collider.obj create mode 120000 hifi-content/huffman/ctf/models/portalgun_red.fbx create mode 100644 hifi-content/huffman/ctf/origina_portal_gun.js create mode 100644 hifi-content/huffman/ctf/portalBulletClientEntity.js create mode 100644 hifi-content/huffman/ctf/portalGunClientEntity.js create mode 100644 hifi-content/huffman/ctf/portalgun.json create mode 100644 hifi-content/huffman/ctf/sounds/gunFire.wav create mode 100644 hifi-content/huffman/ctf/sounds/pong_sound.wav create mode 100644 hifi-content/huffman/ctf/sounds/teleport.raw create mode 100644 hifi-content/huffman/ctf/spawnPortalGun.js create mode 100644 hifi-content/huffman/ctf/utils.js create mode 100644 hifi-content/huffman/essTest.js diff --git a/hifi-content/hifi-worklist-logo.jpg b/hifi-content/hifi-worklist-logo.jpg new file mode 100644 index 000000000..aea9a6f10 --- /dev/null +++ b/hifi-content/hifi-worklist-logo.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55e0762d0f18abcc9774c54991707b651ddde44aecb3f659bdf74ffb6b902e4e +size 57744 diff --git a/hifi-content/high-fidelity-og.jpg b/hifi-content/high-fidelity-og.jpg new file mode 100644 index 000000000..51847777a --- /dev/null +++ b/hifi-content/high-fidelity-og.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11dea34a973c9a92a8763d60e0fa83d008c256f67666be8fabf0ff877314808f +size 249288 diff --git a/hifi-content/high-fidelity-og_load-test.jpg b/hifi-content/high-fidelity-og_load-test.jpg new file mode 100644 index 000000000..8057cf6a5 --- /dev/null +++ b/hifi-content/high-fidelity-og_load-test.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:723ed0248227f0b23c10c8f588fc52e4b99c152a11ab86da5d6e0da9fb552b65 +size 191882 diff --git a/hifi-content/howard/production/zaru-content-custom-scripts.zip b/hifi-content/howard/production/zaru-content-custom-scripts.zip new file mode 120000 index 000000000..7804ca9ad --- /dev/null +++ b/hifi-content/howard/production/zaru-content-custom-scripts.zip @@ -0,0 +1 @@ +../zaru-content-custom-scripts.zip \ No newline at end of file diff --git a/hifi-content/howard/resources/avatar/animations/idle.fbx b/hifi-content/howard/resources/avatar/animations/idle.fbx new file mode 120000 index 000000000..28932e2a2 --- /dev/null +++ b/hifi-content/howard/resources/avatar/animations/idle.fbx @@ -0,0 +1 @@ +../../../../DomainContent/AvatarStore-Backup/BodyMart/idle.fbx \ No newline at end of file diff --git a/hifi-content/howard/resources/avatar/animations/walk_fwd.fbx b/hifi-content/howard/resources/avatar/animations/walk_fwd.fbx new file mode 100644 index 000000000..c46983c2d --- /dev/null +++ b/hifi-content/howard/resources/avatar/animations/walk_fwd.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41e68ef30fcab9aca97307fa815f401477aa7550668beb2af8b35c7a1bd112e5 +size 309024 diff --git a/hifi-content/howard/resources/meshes/being_of_light/being_of_light.fbx b/hifi-content/howard/resources/meshes/being_of_light/being_of_light.fbx new file mode 120000 index 000000000..adc65df8f --- /dev/null +++ b/hifi-content/howard/resources/meshes/being_of_light/being_of_light.fbx @@ -0,0 +1 @@ +../../../../lincoln/avatars/being_of_light.fbx \ No newline at end of file diff --git a/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_DiffuseMap.png b/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_DiffuseMap.png new file mode 120000 index 000000000..8f6222018 --- /dev/null +++ b/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_DiffuseMap.png @@ -0,0 +1 @@ +../../../../../Avatars/production/being_of_light/textures/BaseMesh_BeingofLight_DiffuseMap.png \ No newline at end of file diff --git a/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_EmissiveMap.png b/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_EmissiveMap.png new file mode 120000 index 000000000..55f17c005 --- /dev/null +++ b/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_EmissiveMap.png @@ -0,0 +1 @@ +../../../../../Avatars/production/being_of_light/textures/BaseMesh_BeingofLight_EmissiveMap.png \ No newline at end of file diff --git a/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_NormalMap.png b/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_NormalMap.png new file mode 120000 index 000000000..fedb67990 --- /dev/null +++ b/hifi-content/howard/resources/meshes/being_of_light/textures/BaseMesh_BeingofLight_NormalMap.png @@ -0,0 +1 @@ +../../../../../Avatars/production/being_of_light/textures/BaseMesh_BeingofLight_NormalMap.png \ No newline at end of file diff --git a/hifi-content/howard/resources/meshes/defaultAvatar_full.fst b/hifi-content/howard/resources/meshes/defaultAvatar_full.fst new file mode 120000 index 000000000..22ea22bcf --- /dev/null +++ b/hifi-content/howard/resources/meshes/defaultAvatar_full.fst @@ -0,0 +1 @@ +../../../lincoln/avatars/being_of_light.fst \ No newline at end of file diff --git a/hifi-content/howard/scripts/dev-welcome.js b/hifi-content/howard/scripts/dev-welcome.js new file mode 100644 index 000000000..4dbcf12ad --- /dev/null +++ b/hifi-content/howard/scripts/dev-welcome.js @@ -0,0 +1,64 @@ +var typeBlacklist = ["Zone"]; /* for now, disallow all zone entities */ +var center = {x: 0, y: 0, z: 0}; /* also nothing can move within 5 meters of 0,0,0 */ +var radius = 5; +var epsilon = 0.01; +var aBitMore = 5 * (1 + epsilon); +var staticBounceSpeed = 0.5; /* If edit within radius that has no velocity. */ +var Vec3 = { + distance: function distance(a, b) { + var x = a.x - b.x, + y = a.y - b.y, + z = a.z - b.z; + return Math.sqrt((x * x) + (y * y) + (z * z)); + }, + ZERO: {x: 0, y: 0, z: 0}, + length: function length(v) { + return Vec3.distance(Vec3.ZERO, v); + }, + multiply: function multiply(s, v) { + return {x: s * v.x, y: s * v.y, z: s * v.z}; + }, + normalize: function normalize(v) { + var length = Vec3.length(v); + return Vec3.multiply(1/length, v); + } +}; + +function filter(p, filterType) { + if (p.type && (typeBlacklist.indexOf(p.type) != -1)) { + print("filtering out " + p.type + " entity!"); + return false + } + if (p.position) { + var distance = Vec3.distance(center, p.position); + var reject = distance <= radius; + var normal; + if (reject) { + print('rejecting type', filterType, 'packet near origin'); + if (filterType === Entities.ADD_FILTER_TYPE) { + return false; + } else { /* Others are Entities.EDIT_FILTER_TYPE and Entities.PHYSICS_FILTER_TYPE. */ + normal = Vec3.normalize(p.position); + p.position = Vec3.multiply(aBitMore, normal); + p.velocity = (p.velocity && Vec3.length(p.velocity) > epsilon) ? + Vec3.multiply(-1, p.velocity) : Vec3.multiply(staticBounceSpeed, normal); + p.acceleration = Vec3.ZERO; + } + } + } + if (p.dimensions && (filterType !== Entities.ADD_FILTER_TYPE)) { + if (p.dimensions.x > 11) { + p.dimensions.x = 11; + print('capping x dimension'); + } + if (p.dimensions.y > 11) { + p.dimensions.y = 11; + print('capping y dimension'); + } + if (p.dimensions.z > 11) { + p.dimensions.z = 11; + print('capping z dimension'); + } + } + return p; +} diff --git a/hifi-content/howard/scripts/tests/performance/crowd-agent.js b/hifi-content/howard/scripts/tests/performance/crowd-agent.js new file mode 100644 index 000000000..708856a82 --- /dev/null +++ b/hifi-content/howard/scripts/tests/performance/crowd-agent.js @@ -0,0 +1,166 @@ +"use strict"; +/*jslint vars: true, plusplus: true*/ +/*global Agent, Avatar, Script, Entities, Vec3, Quat, print*/ +// +// crowd-agent.js +// scripts/developer/tests/performance/ +// +// Created by Howard Stearns on 9/29/16. +// Copyright 2016 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 +// +// Add this to domain-settings scripts url with n instances. It will lie dormant until +// a script like summon.js calls up to n avatars to be around you. + +var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; + +print('crowd-agent version 5'); + +/* Observations: +- File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development. +- URLs are cached regardless of server headers. Must use cache-defeating query parameters. +- JSON.stringify(Avatar) silently fails (even when Agent.isAvatar) +- If you run from a dev build directory, you must link assignment-client/<target>/resources to ../../interface/<target>/resources +*/ + +function messageSend(message) { + Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message)); +} + +function getSound(data, callback) { // callback(sound) when downloaded (which may be immediate). + var sound = SoundCache.getSound(data.url); + if (sound.downloaded) { + return callback(sound); + } + function onDownloaded() { + sound.ready.disconnect(onDownloaded); + callback(sound); + } + sound.ready.connect(onDownloaded); +} +function onFinishedPlaying() { + messageSend({key: 'finishedSound'}); +} + +var attachment; +var stopper; +function clearStopper() { + if (!stopper) { + return; + } + Script.clearTimeout(stopper); + stopper = null; +} +function stopAgent(parameters) { + function stop() { + clearStopper(); + if (attachment) { + Avatar.detachOne(attachment.modelURL, attachment.jointName); + attachment = undefined; + } + Agent.isListeningToAudioStream = false; + Agent.isAvatar = false; + print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent)); + } + // Shutting down lots of agents at once can be hard on other parts of the system. (See fogbugz 2095.) + // For now, accept a parameter to delay for the given number of milliseconds before stopping. + // (We cannot count on summoning scripts to spread out the STOP messages, because they might be doing so + // on scriptEnding, in which case they are not allowed to create new delays.) + if (parameters.delay) { + if (!stopper) { // Let the first stopper do the deed. + stopper = Script.setTimeout(stop, parameters.delay); + } + } else { + stop(); + } +} + + +var MILLISECONDS_IN_SECOND = 1000; +function startAgent(parameters) { // Can also be used to update. + print('crowd-agent starting params', JSON.stringify(parameters), JSON.stringify(Agent)); + clearStopper(); + var wasOff = !Agent.isAvatar; + Agent.isAvatar = true; + if (parameters.displayName !== undefined) { + Avatar.displayName = parameters.displayName; + } + if (parameters.position) { + Avatar.position = parameters.position; + } + if (parameters.orientation) { + Avatar.orientation = parameters.orientation; + } + if (parameters.skeletonModelURL) { + Avatar.skeletonModelURL = parameters.skeletonModelURL; + } + if (parameters.listen != undefined) { + Agent.isListeningToAudioStream = parameters.listen; // Send silence when not chattering. + } else if (wasOff) { + Agent.isListeningToAudioStream = true; + } + if (parameters.soundData) { + getSound(parameters.soundData, function (sound) { + Script.setTimeout(onFinishedPlaying, sound.duration * MILLISECONDS_IN_SECOND); + Agent.playAvatarSound(sound); + }); + } + if (parameters.animationData) { + var data = parameters.animationData; + Avatar.startAnimation(data.url, data.fps || 30, 1.0, (data.loopFlag === undefined) ? true : data.loopFlag, false, data.startFrame || 0, data.endFrame); + } + if (parameters.attachment) { + attachment = parameters.attachment; + Avatar.attach(attachment.modelURL, attachment.jointName, attachment.translation, attachment.rotation, attachment.scale, attachment.isSoft); + } else { + attachment = undefined; + } + print('crowd-agent avatars started'); +} + +function messageHandler(channel, messageString, senderID) { + if (channel !== MESSAGE_CHANNEL) { + return; + } + print('crowd-agent message', channel, messageString, senderID); + if (Agent.sessionUUID === senderID) { // ignore my own + return; + } + var message = {}; + try { + message = JSON.parse(messageString); + } catch (e) { + print(e); + } + switch (message.key) { + case "HELO": + messageSend({key: 'hello'}); // Allow the coordinator to count responses and make assignments. + break; + case 'hello': // ignore responses (e.g., from other agents) + case 'finishedSound': + break; + case "SUMMON": + if (message.rcpt === Agent.sessionUUID) { + startAgent(message); + } + break; + case "STOP": + if (message.rcpt === Agent.sessionUUID) { + stopAgent(message); + } + break; + default: + print("crowd-agent received unrecognized message:", channel, messageString, senderID); + } +} +Messages.subscribe(MESSAGE_CHANNEL); +Messages.messageReceived.connect(messageHandler); + +Script.scriptEnding.connect(function () { + print('crowd-agent shutting down'); + Messages.messageReceived.disconnect(messageHandler); + Messages.unsubscribe(MESSAGE_CHANNEL); + print('crowd-agent unsubscribed'); +}); diff --git a/hifi-content/howard/scripts/tests/performance/domain-check.js b/hifi-content/howard/scripts/tests/performance/domain-check.js new file mode 100644 index 000000000..b4bf4569c --- /dev/null +++ b/hifi-content/howard/scripts/tests/performance/domain-check.js @@ -0,0 +1,345 @@ +"use strict"; +/*jslint vars: true, plusplus: true*/ +/*globals Script, MyAvatar, Quat, Vec3, Render, ScriptDiscoveryService, Window, LODManager, Entities, Messages, AvatarList, Menu, Stats, HMD, location, print*/ +// +// loadedMachine.js +// scripts/developer/tests/ +// +// Created by Howard Stearns on 6/6/16. +// Copyright 2016 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 +// +// Confirms that the specified domain is operating within specified constraints. + +var MINIMUM_DESKTOP_FRAMERATE = 57; // frames per second +var MINIMUM_HMD_FRAMERATE = 86; +var EXPECTED_DESKTOP_FRAMERATE = 60; +var EXPECTED_HMD_FRAMERATE = 90; +var NOMINAL_LOAD_TIME = 30; // seconds +var MAXIMUM_LOAD_TIME = NOMINAL_LOAD_TIME * 2; +var MINIMUM_AVATARS = 25; // changeable by prompt + +// If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095). +// For now, spread them out this timing apart. +var SPREAD_TIME_MS = 500; + +var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's length (0.9m^2), 4.5 is crowd (0.4m^2), 2.5 is mosh pit (0.2m^2). +var SOUND_DATA = {url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"}; +var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND at once. +var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next +var ANIMATION_DATA = { + "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/idle.fbx", + // "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/walk_fwd.fbx", // alternative example + "startFrame": 0.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true +}; + +var version = 4; +function debug() { + print.apply(null, [].concat.apply(['hrs fixme', version], [].map.call(arguments, JSON.stringify))); +} + +function canonicalizePlacename(name) { + var prefix = 'dev-'; + name = name.toLowerCase(); + if (name.indexOf(prefix) === 0) { + name = name.slice(prefix.length); + } + return name; +} +var cachePlaces = ['localhost', 'welcome'].map(canonicalizePlacename); // For now, list the lighter weight one first. +var defaultPlace = location.hostname; +var prompt = "domain-check.js version " + version + "\n\nWhat place should we enter?"; +debug(cachePlaces, defaultPlace, prompt); +var entryPlace = Window.prompt(prompt, defaultPlace); +var runTribbles = Window.confirm("Run tribbles?\n\n\ +At most, only one participant should say yes."); +MINIMUM_AVATARS = parseInt(Window.prompt("Total avatars (including yourself and any already present)?", MINIMUM_AVATARS.toString()) || "0", 10); +AVATARS_CHATTERING_AT_ONCE = MINIMUM_AVATARS ? parseInt(Window.prompt("Number making sound?", Math.min(MINIMUM_AVATARS - 1, AVATARS_CHATTERING_AT_ONCE).toString()) || "0", 10) : 0; + +function placesMatch(a, b) { // handling case and 'dev-' variations + return canonicalizePlacename(a) === canonicalizePlacename(b); +} +function isNowIn(place) { // true if currently in specified place + placesMatch(location.hostname, place); +} + +function go(place) { // handle (dev-)welcome in the appropriate version-specific way + debug('go', place); + if (placesMatch(place, 'welcome')) { + location.goToEntry(); + } else { + location.handleLookupString(place); + } +} + +var spread = Math.sqrt(MINIMUM_AVATARS * DENSITY); // meters +var turnSpread = 90; // How many degrees should turn from front range over. + +function coord() { return (Math.random() * spread) - (spread / 2); } // randomly distribute a coordinate zero += spread/2. +function contains(array, item) { return array.indexOf(item) >= 0; } +function without(array, itemsToRemove) { return array.filter(function (item) { return !contains(itemsToRemove, item); }); } +function nextAfter(array, id) { // Wrapping next element in array after id. + var index = array.indexOf(id) + 1; + return array[(index >= array.length) ? 0 : index]; +} + +var summonedAgents = []; +var chattering = []; +var accumulatedDelay = 0; +var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; +function messageSend(message) { + Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message)); +} +function messageHandler(channel, messageString, senderID) { + if (channel !== MESSAGE_CHANNEL) { + return; + } + debug('message', channel, messageString, senderID); + if (MyAvatar.sessionUUID === senderID) { // ignore my own + return; + } + var message = {}, avatarIdentifiers; + try { + message = JSON.parse(messageString); + } catch (e) { + print(e); + } + switch (message.key) { + case "hello": + Script.setTimeout(function () { + // There can be avatars we've summoned that do not yet appear in the AvatarList. + avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents); + debug('present', avatarIdentifiers, summonedAgents); + if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS) { + var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE; + if (chatter) { + chattering.push(senderID); + } + summonedAgents.push(senderID); + messageSend({ + key: 'SUMMON', + rcpt: senderID, + position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}), + orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0), + soundData: chatter && SOUND_DATA, + listen: true, + skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst", + animationData: ANIMATION_DATA + }); + } + }, accumulatedDelay); + accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together. + break; + case "finishedSound": // Give someone else a chance. + chattering = without(chattering, [senderID]); + Script.setTimeout(function () { + messageSend({ + key: 'SUMMON', + rcpt: nextAfter(without(summonedAgents, chattering), senderID), + soundData: SOUND_DATA + }); + }, Math.random() * NEXT_SOUND_SPREAD); + break; + case "HELO": + Window.alert("Someone else is summoning avatars."); + break; + default: + print("crowd-agent received unrecognized message:", messageString); + } +} +Messages.subscribe(MESSAGE_CHANNEL); +Messages.messageReceived.connect(messageHandler); +Script.scriptEnding.connect(function () { + debug('stopping agents', summonedAgents); + Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown + accumulatedDelay = 0; + summonedAgents.forEach(function (id) { + messageSend({key: 'STOP', rcpt: id, delay: accumulatedDelay}); + accumulatedDelay += SPREAD_TIME_MS; + }); + debug('agents stopped'); + Messages.unsubscribe(MESSAGE_CHANNEL); + debug('unsubscribed'); +}); + +var fail = false, results = ""; +function addResult(label, actual, nominal, minimum, maximum) { + if ((minimum !== undefined) && (actual < minimum)) { + fail = ' FAILED: ' + label + ' below ' + minimum; + } + if ((maximum !== undefined) && (actual > maximum)) { + fail = ' FAILED: ' + label + ' above ' + maximum; + } + results += "\n" + label + ": " + actual.toFixed(0) + " (" + ((100 * actual) / nominal).toFixed(0) + "%)"; +} +function giveReport() { + Window.alert(entryPlace + (fail || " OK") + "\n" + results + "\nwith " + summonedAgents.length + " avatars added,\nand " + AVATARS_CHATTERING_AT_ONCE + " making noise."); +} + +// Tests are performed domain-wide, at full LOD +var initialLodIsAutomatic = LODManager.getAutomaticLODAdjust(); +var LOD = 32768 * 400; +LODManager.setAutomaticLODAdjust(false); +LODManager.setOctreeSizeScale(LOD); +Script.scriptEnding.connect(function () { LODManager.setAutomaticLODAdjust(initialLodIsAutomatic); }); + +function startTwirl(targetRotation, degreesPerUpdate, interval, strafeDistance, optionalCallback) { + var initialRotation = Quat.safeEulerAngles(MyAvatar.orientation).y; + var accumulatedRotation = 0; + function tick() { + MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, accumulatedRotation + initialRotation, 0); + if (strafeDistance) { + MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(strafeDistance, Quat.getRight(MyAvatar.orientation))); + } + accumulatedRotation += degreesPerUpdate; + if (accumulatedRotation >= targetRotation) { + return optionalCallback && optionalCallback(); + } + Script.setTimeout(tick, interval); + } + tick(); +} + +function doLoad(place, continuationWithLoadTime) { // Go to place and call continuationWithLoadTime(loadTimeInSeconds) + var start = Date.now(), timeout, onDownloadUpdate, finishedTwirl = false, loadTime; + // There are two ways to learn of changes: connect to change signals, or poll. + // Until we get reliable results, we'll poll. + var POLL_INTERVAL = 500, poll; + function setHandlers() { + //Stats.downloadsPendingChanged.connect(onDownloadUpdate); downloadsChanged, and physics... + poll = Script.setInterval(onDownloadUpdate, POLL_INTERVAL); + } + function clearHandlers() { + debug('clearHandlers'); + //Stats.downloadsPendingChanged.disconnect(onDownloadUpdate); downloadsChanged, and physics.. + Script.clearInterval(poll); + } + function waitForLoad(flag) { + debug('entry', place, 'initial downloads/pending', Stats.downloads, Stats.downloadsPending); + location.hostChanged.disconnect(waitForLoad); + timeout = Script.setTimeout(function () { + debug('downloads timeout', Date()); + clearHandlers(); + Window.alert("Timeout during " + place + " load. FAILED"); + Script.stop(); + }, MAXIMUM_LOAD_TIME * 1000); + startTwirl(360, 6, 90, null, function () { + finishedTwirl = true; + if (loadTime) { + continuationWithLoadTime(loadTime); + } + }); + setHandlers(); + } + function isLoading() { + // FIXME: We should also confirm that textures have loaded. + return Stats.downloads || Stats.downloadsPending || !Window.isPhysicsEnabled(); + } + onDownloadUpdate = function onDownloadUpdate() { + debug('update downloads/pending', Stats.downloads, Stats.downloadsPending); + if (isLoading()) { + return; + } + Script.clearTimeout(timeout); + clearHandlers(); + loadTime = (Date.now() - start) / 1000; + if (finishedTwirl) { + continuationWithLoadTime(loadTime); + } + }; + + location.hostChanged.connect(waitForLoad); + go(place); +} + +var config = Render.getConfig("Stats"); +function doRender(continuation) { + var start = Date.now(), frames = 0; + function onNewStats() { // Accumulates frames on signal during load test + frames++; + } + if (MINIMUM_AVATARS) { + messageSend({key: 'HELO'}); // Ask agents to report in now. + } + + config.newStats.connect(onNewStats); + startTwirl(720, 1, 20, 0.08, function () { + var end = Date.now(); + config.newStats.disconnect(onNewStats); + addResult('frame rate', 1000 * frames / (end - start), + HMD.active ? EXPECTED_HMD_FRAMERATE : EXPECTED_DESKTOP_FRAMERATE, + HMD.active ? MINIMUM_HMD_FRAMERATE : MINIMUM_DESKTOP_FRAMERATE); + var total = AvatarList.getAvatarIdentifiers().length; + if (MINIMUM_AVATARS && !fail) { + if (0 === summonedAgents.length) { + fail = "FAIL: No agents reported.\nPlease run " + MINIMUM_AVATARS + " instances of\n\ +http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=3\n\ +on your domain server."; + } else if (total < MINIMUM_AVATARS) { + fail = "FAIL: Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total."; + } + } + continuation(); + }); +} + +var TELEPORT_PAUSE = 500; +function prepareCache(continuation) { + function loadNext() { + var place = cachePlaces.shift(); + doLoad(place, function (prepTime) { + debug(place, 'ready', prepTime); + if (cachePlaces.length) { + loadNext(); + } else { + continuation(); + } + }); + } + // remove entryPlace target from cachePlaces + var targetInCache = cachePlaces.indexOf(canonicalizePlacename(entryPlace)); + if (targetInCache !== -1) { + cachePlaces.splice(targetInCache, 1); + } + debug('cachePlaces', cachePlaces); + go(cachePlaces[1] || entryPlace); // Not quite right for entryPlace case (allows some qt pre-caching), but close enough. + Script.setTimeout(function () { + Menu.triggerOption("Reload Content (Clears all caches)"); + Script.setTimeout(loadNext, TELEPORT_PAUSE); + }, TELEPORT_PAUSE); +} + +function maybeRunTribbles(continuation) { + if (runTribbles) { + Script.load('http://cdn.highfidelity.com/davidkelly/production/scripts/tests/performance/tribbles.js'); + Script.setTimeout(continuation, 3000); + } else { + continuation(); + } +} + +if (!entryPlace) { + Window.alert("domain-check.js cancelled"); + Script.stop(); +} else { + prepareCache(function (prepTime) { + debug('cache ready', prepTime); + doLoad(entryPlace, function (loadTime) { + addResult("load time", loadTime, NOMINAL_LOAD_TIME, undefined, MAXIMUM_LOAD_TIME); + LODManager.setAutomaticLODAdjust(initialLodIsAutomatic); // after loading, restore lod. + maybeRunTribbles(function () { + doRender(function () { + giveReport(); + Script.stop(); + }); + }); + }); + }); +} + +Script.scriptEnding.connect(function () { print("domain-check completed"); }); diff --git a/hifi-content/howard/scripts/tests/performance/screamingAvatarAC.js b/hifi-content/howard/scripts/tests/performance/screamingAvatarAC.js new file mode 100644 index 000000000..40210ef02 --- /dev/null +++ b/hifi-content/howard/scripts/tests/performance/screamingAvatarAC.js @@ -0,0 +1,39 @@ +var sound = SoundCache.getSound("http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"); + +var ANIMATION_URL = "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/idle.fbx"; +var AVATAR_MODEL = "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst"; +var POLL_INTERVAL = 500; // ms +var SPREAD_MAX = 2; +var SPREAD_MIN = 0; +var SOUND_PAUSE_MAX = 10000; +var SOUND_PAUSE_MIN = 2000; + +function randInterval(min, max) { + return min + Math.random()*(max-min); +} + +Agent.isAvatar = true; +Agent.isListening = true; + +Avatar.skeletonModelURL = AVATAR_MODEL; +Avatar.position = { x: randInterval(SPREAD_MIN, SPREAD_MAX), + y: randInterval(SPREAD_MIN, SPREAD_MAX), + z: randInterval(SPREAD_MIN, SPREAD_MAX) +}; + +Avatar.startAnimation(ANIMATION_URL, 30, 1.0, true, false, 0, 300); + +var soundInterval = Script.setInterval(function () { + if (sound.downloaded) { + Script.clearInterval(soundInterval); + print("sound downloaded"); + // now play it in a loop until the end of time + Script.setInterval(function() { + print("playing sound"); + Agent.playAvatarSound(sound); + }, sound.duration + randInterval(SOUND_PAUSE_MIN, SOUND_PAUSE_MAX)); + } else { + print("waiting for sound to download..."); + } +}, POLL_INTERVAL); + diff --git a/hifi-content/howard/scripts/tests/performance/summon.js b/hifi-content/howard/scripts/tests/performance/summon.js new file mode 100644 index 000000000..29b61bf2c --- /dev/null +++ b/hifi-content/howard/scripts/tests/performance/summon.js @@ -0,0 +1,157 @@ +"use strict"; +/*jslint vars: true, plusplus: true*/ +/*global Agent, Avatar, Script, Entities, Vec3, Quat, print*/ +// +// crowd-agent.js +// scripts/developer/tests/performance/ +// +// Created by Howard Stearns on 9/29/16. +// Copyright 2016 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 +// +// See crowd-agent.js + +var version = 3; +var label = "summon"; +function debug() { + print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify))); +} + +var MINIMUM_AVATARS = 25; // We will summon agents to produce this many total. (Of course, there might not be enough agents.) +var N_LISTENING = MINIMUM_AVATARS - 1; +var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND_DATA at once. + +var initialBubble = Users.getIgnoreRadiusEnabled(); +debug('startup seeking:', MINIMUM_AVATARS, 'listening:', N_LISTENING, 'chattering:', AVATARS_CHATTERING_AT_ONCE, 'had bubble:', initialBubble); + +// If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095). +// For now, spread them out this timing apart. +var SPREAD_TIME_MS = 500; + +var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's length (0.9m^2), 4.5 is crowd (0.4m^2), 2.5 is mosh pit (0.2m^2). +var SOUND_DATA = {url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"}; +var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next +var ANIMATION_DATA = { + "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/idle.fbx", + // "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/walk_fwd.fbx", // alternative example + "startFrame": 0.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true +}; + +var spread = Math.sqrt(MINIMUM_AVATARS * DENSITY); // meters +var turnSpread = 90; // How many degrees should turn from front range over. + +function coord() { return (Math.random() * spread) - (spread / 2); } // randomly distribute a coordinate zero += spread/2. +function contains(array, item) { return array.indexOf(item) >= 0; } +function without(array, itemsToRemove) { return array.filter(function (item) { return !contains(itemsToRemove, item); }); } +function nextAfter(array, id) { // Wrapping next element in array after id. + var index = array.indexOf(id) + 1; + return array[(index >= array.length) ? 0 : index]; +} + +var summonedAgents = []; +var chattering = []; +var nListening = 0; +var accumulatedDelay = 0; +var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; +function messageSend(message) { + Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message)); +} +function messageHandler(channel, messageString, senderID) { + if (channel !== MESSAGE_CHANNEL) { + return; + } + debug('message', channel, messageString, senderID); + if (MyAvatar.sessionUUID === senderID) { // ignore my own + return; + } + var message = {}; + try { + message = JSON.parse(messageString); + } catch (e) { + print(e); + } + switch (message.key) { + case "hello": + Script.setTimeout(function () { + // There can be avatars we've summoned that do not yet appear in the AvatarList. + var avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents); + var nSummoned = summonedAgents.length; + debug('present', avatarIdentifiers, summonedAgents); + if ((nSummoned + avatarIdentifiers.length) < MINIMUM_AVATARS ) { + var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE; + var listen = nListening < N_LISTENING; + if (chatter) { + chattering.push(senderID); + } + if (listen) { + nListening++; + } + summonedAgents.push(senderID); + messageSend({ + key: 'SUMMON', + rcpt: senderID, + displayName: "crowd " + nSummoned + " " + senderID, + position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}), + orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0), + soundData: chatter && SOUND_DATA, + listen: listen, + skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst", + animationData: ANIMATION_DATA + }); + } + }, accumulatedDelay); + accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello responses more or less together. + break; + case "finishedSound": // Give someone else a chance. + chattering = without(chattering, [senderID]); + Script.setTimeout(function () { + messageSend({ + key: 'SUMMON', + rcpt: nextAfter(without(summonedAgents, chattering), senderID), + soundData: SOUND_DATA + }); + }, Math.random() * NEXT_SOUND_SPREAD); + break; + case "HELO": + Window.alert("Someone else is summoning avatars."); + break; + default: + print("crowd summon.js received unrecognized message:", messageString); + } +} +Messages.subscribe(MESSAGE_CHANNEL); +Messages.messageReceived.connect(messageHandler); +Script.scriptEnding.connect(function () { + debug('stopping agents', summonedAgents); + Users.requestsDomainListData = false; + if (initialBubble && !Users.getIgnoreRadiusEnabled()) { Users.toggleIgnoreRadius(); } + Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown + accumulatedDelay = 0; + summonedAgents.forEach(function (id) { + messageSend({key: 'STOP', rcpt: id, delay: accumulatedDelay}); + accumulatedDelay += SPREAD_TIME_MS; + }); + debug('agents stopped'); + Messages.unsubscribe(MESSAGE_CHANNEL); + debug('unsubscribed'); +}); + +Users.requestsDomainListData = true; // Get avatar data for the whole domain, even if not in our view. +if (initialBubble) { Users.toggleIgnoreRadius(); } +messageSend({key: 'HELO'}); // Ask agents to report in now. +Script.setTimeout(function () { + var total = AvatarList.getAvatarIdentifiers().length; + if (0 === summonedAgents.length) { + Window.alert("No agents reported.\n\Please run " + MINIMUM_AVATARS + " instances of\n\ +http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=someDate\n\ +on your domain server."); + } else if (total < MINIMUM_AVATARS) { + Window.alert("Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total."); + } + Users.requestsDomainListData = false; +}, MINIMUM_AVATARS * SPREAD_TIME_MS ) diff --git a/hifi-content/howard/sounds/hello.wav b/hifi-content/howard/sounds/hello.wav new file mode 100644 index 000000000..a995e7d65 --- /dev/null +++ b/hifi-content/howard/sounds/hello.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bbd7c78a54c8b62d509c102301a2c4647d4450abe314b2c3f869d755bdfacf9 +size 231196 diff --git a/hifi-content/howard/sounds/piano1.wav b/hifi-content/howard/sounds/piano1.wav new file mode 100644 index 000000000..57de26dcf --- /dev/null +++ b/hifi-content/howard/sounds/piano1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f0c3614f197c953bf2abfddfd262ede87b94d195afb4d5a32aa1bcbbee5e38a0 +size 605468 diff --git a/hifi-content/howard/zaru-content-custom-scripts.zip b/hifi-content/howard/zaru-content-custom-scripts.zip new file mode 100644 index 000000000..35ccca50a --- /dev/null +++ b/hifi-content/howard/zaru-content-custom-scripts.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3afc07ec2d54a3e4f8d4c63a2348c98319184bf20ab0b14eea1e6cf183b248c4 +size 57483884 diff --git a/hifi-content/howard/zaru-content-default-scripts.zip b/hifi-content/howard/zaru-content-default-scripts.zip new file mode 100644 index 000000000..d16b101b9 --- /dev/null +++ b/hifi-content/howard/zaru-content-default-scripts.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66cc1ca2df52b52db588d3a0b27d75a478648a5a4f3bbdea1905edbddef36563 +size 57483371 diff --git a/hifi-content/howell/Prototypes/Cartoony_Computer/CCTV_image-redigert.jpg b/hifi-content/howell/Prototypes/Cartoony_Computer/CCTV_image-redigert.jpg new file mode 100644 index 000000000..31cbf3738 --- /dev/null +++ b/hifi-content/howell/Prototypes/Cartoony_Computer/CCTV_image-redigert.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90f6c2a8798894aaa28d56638ea63e0beed0baf83bc76876046cc3c1cc52179c +size 554614 diff --git a/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.FBX b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.FBX new file mode 100644 index 000000000..75593922e --- /dev/null +++ b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.FBX @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c975e55ed89259df4ec3ea70a6cab91d10b5dacb705c6de7f2fb60b211324fc +size 536048 diff --git a/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.max b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.max new file mode 100644 index 000000000..8f8340149 --- /dev/null +++ b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.max @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:443d4bc32914392ae60cf9eb5dae38188b3fc3afb5fd23601d03b489520894e2 +size 1925120 diff --git a/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.mtl b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.mtl new file mode 100644 index 000000000..914a843e5 --- /dev/null +++ b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.mtl @@ -0,0 +1,84 @@ +# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware +# File Created: 19.03.2013 20:37:19 + +newmtl Material__223 + Ns 10.0000 + Ni 1.5000 + d 1.0000 + Tr 0.0000 + Tf 1.0000 1.0000 1.0000 + illum 2 + Ka 0.5880 0.5880 0.5880 + Kd 0.7765 0.7765 0.7765 + Ks 0.0000 0.0000 0.0000 + Ke 0.0000 0.0000 0.0000 + +newmtl CCTV_screen + Ns 10.0000 + Ni 1.5000 + d 1.0000 + Tr 0.0000 + Tf 1.0000 1.0000 1.0000 + illum 2 + Ka 0.5880 0.5880 0.5880 + Kd 0.1137 0.1137 0.1137 + Ks 0.0000 0.0000 0.0000 + Ke 0.0978 0.0978 0.0978 + map_Ka F:\shared\TurboSquid\Free\Computer\maps\CCTV_image-redigert.jpg + map_Kd F:\shared\TurboSquid\Free\Computer\maps\CCTV_image-redigert.jpg + +newmtl Material__225 + Ns 10.0000 + Ni 1.5000 + d 1.0000 + Tr 0.0000 + Tf 1.0000 1.0000 1.0000 + illum 2 + Ka 0.5880 0.5880 0.5880 + Kd 0.4275 0.4275 0.4275 + Ks 0.0000 0.0000 0.0000 + Ke 0.0000 0.0000 0.0000 + +newmtl Computer_screen + Ns 10.0000 + Ni 1.5000 + d 1.0000 + Tr 0.0000 + Tf 1.0000 1.0000 1.0000 + illum 2 + Ka 0.5880 0.5880 0.5880 + Kd 0.8784 0.8549 0.8118 + Ks 0.0000 0.0000 0.0000 + Ke 0.0000 0.0000 0.0000 + +newmtl wire_154215229 + Ns 32 + d 1 + Tr 0 + Tf 1 1 1 + illum 2 + Ka 0.6039 0.8431 0.8980 + Kd 0.6039 0.8431 0.8980 + Ks 0.3500 0.3500 0.3500 + +newmtl wire_177088027 + Ns 32 + d 1 + Tr 0 + Tf 1 1 1 + illum 2 + Ka 0.6941 0.3451 0.1059 + Kd 0.6941 0.3451 0.1059 + Ks 0.3500 0.3500 0.3500 + +newmtl RedButton + Ns 10.0000 + Ni 1.5000 + d 1.0000 + Tr 0.0000 + Tf 1.0000 1.0000 1.0000 + illum 2 + Ka 0.5880 0.5880 0.5880 + Kd 1.0000 0.0000 0.0000 + Ks 0.0000 0.0000 0.0000 + Ke 0.0000 0.0000 0.0000 diff --git a/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.obj b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.obj new file mode 100644 index 000000000..8ce0e9c4f --- /dev/null +++ b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c62744991df8b49dfe081027be0aacbc066864f401e4d15fd0845d3026de3cbc +size 952242 diff --git a/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer[max2010].max b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer[max2010].max new file mode 100644 index 000000000..63454eedd --- /dev/null +++ b/hifi-content/howell/Prototypes/Cartoony_Computer/Cartoony_Computer[max2010].max @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:950ac518d51b84869f080e6c7c14d62f181475b6ef7422d5520e3574a77777e5 +size 1761280 diff --git a/hifi-content/howell/Prototypes/GOT/GOT.png b/hifi-content/howell/Prototypes/GOT/GOT.png new file mode 100644 index 000000000..baf7e0353 --- /dev/null +++ b/hifi-content/howell/Prototypes/GOT/GOT.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e85deb385b86801c5c5cf0dccafa187c3cc1d9c84b3f8d515e0ca2ac588b747f +size 98997 diff --git a/hifi-content/howell/Prototypes/GOT/drogon finished with base2.obj b/hifi-content/howell/Prototypes/GOT/drogon finished with base2.obj new file mode 100644 index 000000000..8be9a77bc --- /dev/null +++ b/hifi-content/howell/Prototypes/GOT/drogon finished with base2.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ceaa61bde404e2621e5ddbcbbf18224fc1a4d1207093bb5dca55b75c46e7d47d +size 30302889 diff --git a/hifi-content/howell/Prototypes/GOT/drogon-statue.fbx b/hifi-content/howell/Prototypes/GOT/drogon-statue.fbx new file mode 100644 index 000000000..8ac488408 --- /dev/null +++ b/hifi-content/howell/Prototypes/GOT/drogon-statue.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df2e239a3abb3797ece2ddfaca17e7103f0d14aeaa1969d657a474545e0f411c +size 17763132 diff --git a/hifi-content/howell/Prototypes/Idle_app/Hanging Idle.fbx b/hifi-content/howell/Prototypes/Idle_app/Hanging Idle.fbx new file mode 100644 index 000000000..7643ae8c6 --- /dev/null +++ b/hifi-content/howell/Prototypes/Idle_app/Hanging Idle.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93019adf0763112f7082d6e1475f2c4f09f7c34fc3f02fd052cd772935f6b5df +size 439568 diff --git a/hifi-content/howell/Prototypes/Idle_app/Happy.fbx b/hifi-content/howell/Prototypes/Idle_app/Happy.fbx new file mode 100644 index 000000000..e5356ea7f --- /dev/null +++ b/hifi-content/howell/Prototypes/Idle_app/Happy.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9c35753b396373d6646521a69bbca9b9bc8d4e24992925ffdc1941b07c2c9f1 +size 531520 diff --git a/hifi-content/howell/Prototypes/Idle_app/Male Laying Pose.fbx b/hifi-content/howell/Prototypes/Idle_app/Male Laying Pose.fbx new file mode 100644 index 000000000..28395a95f --- /dev/null +++ b/hifi-content/howell/Prototypes/Idle_app/Male Laying Pose.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb9e60eef42c9c5144fd419c8eb00c8c8a79be1dd18ae91ffe9e65383973d725 +size 210944 diff --git a/hifi-content/howell/Prototypes/Idle_app/Ninja Idle.fbx b/hifi-content/howell/Prototypes/Idle_app/Ninja Idle.fbx new file mode 100644 index 000000000..9d7887e20 --- /dev/null +++ b/hifi-content/howell/Prototypes/Idle_app/Ninja Idle.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a580d6c309a0fa3fe1ddba1f41c60693c2573f4203026945cbe583972cad836e +size 652512 diff --git a/hifi-content/howell/Prototypes/Idle_app/Push Up.fbx b/hifi-content/howell/Prototypes/Idle_app/Push Up.fbx new file mode 100644 index 000000000..c14ddde70 --- /dev/null +++ b/hifi-content/howell/Prototypes/Idle_app/Push Up.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2828190ed38048d7387a169b3f34ecf4a34a0830527c062590326dd63767bf96 +size 331072 diff --git a/hifi-content/howell/Prototypes/Idle_app/mat_laying.fbx b/hifi-content/howell/Prototypes/Idle_app/mat_laying.fbx new file mode 100644 index 000000000..f17e21e54 --- /dev/null +++ b/hifi-content/howell/Prototypes/Idle_app/mat_laying.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82be489c57ba5f8ccc90f4fde4214b980cb28e4b610888ea5ff456ed7ebc15b2 +size 210944 diff --git a/hifi-content/howell/Prototypes/JAT_test/JATScritp.js b/hifi-content/howell/Prototypes/JAT_test/JATScritp.js new file mode 100644 index 000000000..6cded211d --- /dev/null +++ b/hifi-content/howell/Prototypes/JAT_test/JATScritp.js @@ -0,0 +1,344 @@ +// +// JATAvatarScript.js +// +// Rezzes JAT's avatars as Overlays, and handle clicking on them. +// +// Created by Zach Fox on 2019-03-15 +// Copyright 2019 High Fidelity, Inc. +// +// See accompanying README.md for usage instructions. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + +(function () { + var BASE_RELATIVE_POSITION = {"x":20.9303035736084,"y":-11.449395179748535,"z":-50.0930061340332}; + + var config = Script.require(Script.resolvePath("config.json?" + Date.now())); + + var AVATAR_OVERLAY_PROPERTIES = [ + { + "type": "Model", + "name": config.avatars[0].name, + "position": { + "x": 0.8213138580322266, + "y": 0.022147178649902344, + "z": 0.5046806335449219 + }, + "dimensions": { + "x": 0.4687473773956299, + "y": 0.797889769077301, + "z": 0.3429218530654907 + }, + "rotation": { + "x": -0.0000457763671875, + "y": -0.2866712212562561, + "z": -0.0000152587890625, + "w": 0.9580377340316772 + }, + "url": config.avatars[0].url, + "isFacingAvatar": false + }, + { + "id": "{d8ad1d89-038e-43c2-87dc-6d38988a71a4}", + "type": "Model", + "name": config.avatars[1].name, + "position": { + "x": 2.492778778076172, + "y": 0.08696365356445312, + "z": 2.8273887634277344 + }, + "dimensions": { + "x": 0.5626906156539917, + "y": 0.9782152771949768, + "z": 0.20142969489097595 + }, + "rotation": { + "x": 0.0000152587890625, + "y": 0.5656976699829102, + "z": -0.0000457763671875, + "w": -0.8246127963066101 + }, + "url": config.avatars[1].url, + "isFacingAvatar": false + }, + { + "id": "{ac2a7754-eec7-4bb6-9550-3af9caa970c9}", + "type": "Model", + "name": config.avatars[2].name, + "position": { + "x": 1.6198616027832031, + "y": 0.17209148406982422, + "z": 1.1371917724609375 + }, + "dimensions": { + "x": 1.1117140054702759, + "y": 0.8896834254264832, + "z": 0.6230975985527039 + }, + "rotation": { + "x": -0.0000457763671875, + "y": -0.423941433429718, + "z": -0.0000457763671875, + "w": 0.9056992530822754 + }, + "url": config.avatars[2].url, + "isFacingAvatar": false + }, + { + "id": "{0b261ed8-4c78-40db-915d-951b819821f5}", + "type": "Model", + "name": config.avatars[3].name, + "position": { + "x": 0, + "y": 0.12828731536865234, + "z": 0 + }, + "dimensions": { + "x": 1.0574196577072144, + "y": 1.1382946968078613, + "z": 0.27917155623435974 + }, + "rotation": { + "x": -0.0000457763671875, + "y": -0.22655069828033447, + "z": -0.0000152587890625, + "w": 0.9739986658096313 + }, + "url": config.avatars[3].url, + "isFacingAvatar": false + }, + { + "id": "{57168289-d40e-467a-8154-c9f1c6868615}", + "type": "Model", + "name": config.avatars[4].name, + "position": { + "x": 2.1323165893554688, + "y": 0, + "z": 2.091522216796875 + }, + "dimensions": { + "x": 0.667604386806488, + "y": 0.8386905193328857, + "z": 0.1569727063179016 + }, + "rotation": { + "x": 0.0000152587890625, + "y": 0.5126268863677979, + "z": -0.0000762939453125, + "w": -0.8586099147796631 + }, + "url": config.avatars[4].url, + "isFacingAvatar": false + } + ]; + + var BUTTON_DIMENSIONS = {"x": 0.2, "y": 0.2, "z": 0.2}; + var BUTTON_ROTATION = Quat.fromPitchYawRollDegrees(180, 140, 180); + var BUTTON_ROTATION_PREV = Quat.fromPitchYawRollDegrees(180, -140, 0); + + var CONTROL_BUTTON_PROPERTIES = [ + { + "name": "play", + "url": "https://hifi-content.s3.amazonaws.com/alan/dev/playback_play-button.fbx", + "position": { + "x": 16.6961, + "y": -11.1147, + "z": -48.6680 + }, + "dimensions": BUTTON_DIMENSIONS, + "rotation": BUTTON_ROTATION + }, + { + "name": "pause", + "url": "https://hifi-content.s3.amazonaws.com/alan/dev/playback_pause-button.fbx", + "position": { + "x": 17.1057, + "y": -11.1149, + "z": -48.9547 + }, + "dimensions": BUTTON_DIMENSIONS, + "rotation": BUTTON_ROTATION + }, + { + "name": "previous", + "url": "https://hifi-content.s3.amazonaws.com/alan/dev/playback_ff-rw-button.fbx", + "position": { + "x": 17.5153, + "y": -11.1150, + "z": -49.2414 + }, + "dimensions": BUTTON_DIMENSIONS, + "rotation": BUTTON_ROTATION_PREV + }, + { + "name": "next", + "url": "https://hifi-content.s3.amazonaws.com/alan/dev/playback_ff-rw-button.fbx", + "position": { + "x": 17.9249, + "y": -11.1151, + "z": -49.5279 + }, + "dimensions": BUTTON_DIMENSIONS, + "rotation": BUTTON_ROTATION + } + ]; + + var TEXT_OVERLAY_PROPERTIES = { + "name": "text", + "lineHeight": 0.10, + "backgroundAlpha": 0.75, + "position": { + "x": 15.7621, + "y": -11.3145, + "z": -48.2583 + }, + "rotation": BUTTON_ROTATION, + "dimensions": { + "x": 1.5, + "y": 0.25, + "z": 1 + }, + "topMargin": 0, + "rightMargin": 0, + "bottomMargin": 0, + "leftMargin": 0 + }; + + var METERS_TO_INCHES = 39.3701; + var WEB_OVERLAY_PROPERTIES = { + "rotation": BUTTON_ROTATION, + "dimensions": { + "x": 1, + "y": 1, + "z": 0 + }, + "position": { + "x": 18.8594, + "y": -11.3154, + "z": -50.4261 + }, + "url": config.screenleapURL, + "dpi": 1920 / (3 * METERS_TO_INCHES), + "alpha": 0.75 + }; + + var rezzedAvatarOverlays = []; + function rezAvatarOverlays() { + for (var i = 0; i < AVATAR_OVERLAY_PROPERTIES.length; i++) { + var currentProps = AVATAR_OVERLAY_PROPERTIES[i]; + currentProps.position = Vec3.sum(currentProps.position, BASE_RELATIVE_POSITION); + console.log("Rezzing overlay with name " + + AVATAR_OVERLAY_PROPERTIES[i].name + " at " + JSON.stringify(currentProps.position)); + rezzedAvatarOverlays.push(Overlays.addOverlay("model", currentProps)); + } + } + + var rezzedControlButtonOverlays = []; + function rezVideoControlButtons() { + for (var i = 0; i < CONTROL_BUTTON_PROPERTIES.length; i++) { + var currentProps = CONTROL_BUTTON_PROPERTIES[i]; + console.log("Rezzing overlay with name " + + CONTROL_BUTTON_PROPERTIES[i].name + " at " + JSON.stringify(currentProps.position)); + rezzedControlButtonOverlays.push(Overlays.addOverlay("model", currentProps)); + } + } + + var textOverlay = false; + function rezTextOverlay() { + console.log("Rezzing overlay with name " + + TEXT_OVERLAY_PROPERTIES.name + " at " + JSON.stringify(TEXT_OVERLAY_PROPERTIES.position)); + textOverlay = Overlays.addOverlay("text3d", TEXT_OVERLAY_PROPERTIES); + } + + var webOverlay = false; + function rezWebOverlay() { + console.log("Rezzing overlay with name " + + WEB_OVERLAY_PROPERTIES.name + " at " + JSON.stringify(WEB_OVERLAY_PROPERTIES.position)); + webOverlay = Overlays.addOverlay("web3d", WEB_OVERLAY_PROPERTIES); + } + + function startup() { + console.log("Welcome to rezJATAvatars.js!"); + + rezAvatarOverlays(); + rezVideoControlButtons(); + rezTextOverlay(); + rezWebOverlay(); + } + + function onScriptEnding() { + for (var i = 0; i < rezzedAvatarOverlays.length; i++) { + console.log("Deleting local entity with ID " + rezzedAvatarOverlays[i]); + Overlays.deleteOverlay(rezzedAvatarOverlays[i]); + } + for (i = 0; i < rezzedAvatarOverlays.length; i++) { + console.log("Deleting local entity with ID " + rezzedControlButtonOverlays[i]); + Overlays.deleteOverlay(rezzedControlButtonOverlays[i]); + } + + if (textOverlay) { + Overlays.deleteOverlay(textOverlay); + } + + if (webOverlay) { + Overlays.deleteOverlay(webOverlay); + } + + Overlays.mousePressOnOverlay.disconnect(onMousePressOnOverlay); + } + + var MESSAGE_CHANNEL = config.controlsMessageChannel; + function handleControlButtonPress(id) { + var name = Overlays.getProperties(id, ["name"]).name; + + switch (name) { + case "play": + Messages.sendMessage(MESSAGE_CHANNEL, 'play'); + break; + + case "pause": + Messages.sendMessage(MESSAGE_CHANNEL, 'pause'); + break; + + case "previous": + Messages.sendMessage(MESSAGE_CHANNEL, 'previous'); + break; + + case "next": + Messages.sendMessage(MESSAGE_CHANNEL, 'next'); + break; + + default: + console.log("Unhandled button overlay pressed"); + } + } + + var STATUS_MESSAGE_CHANNEL = config.statusMessageChannel; + function onMessageReceived(channel, message) { + if (channel === STATUS_MESSAGE_CHANNEL && textOverlay){ + console.log("message", message); + Overlays.editOverlay(textOverlay, {text: message}); + } + } + + function onMousePressOnOverlay(id, event) { + if (!event.button === "Primary") { + return; + } + + if (rezzedAvatarOverlays.indexOf(id) > -1) { + var modelURL = Overlays.getProperties(id, ["url"]).url; + MyAvatar.useFullAvatarURL(modelURL); + } else if (rezzedControlButtonOverlays.indexOf(id) > -1) { + handleControlButtonPress(id); + } + } + + Overlays.mousePressOnOverlay.connect(onMousePressOnOverlay); + Script.scriptEnding.connect(onScriptEnding); + Messages.subscribe(STATUS_MESSAGE_CHANNEL); + Messages.messageReceived.connect(onMessageReceived); + startup(); +})(); diff --git a/hifi-content/howell/Prototypes/JAT_test/config.json b/hifi-content/howell/Prototypes/JAT_test/config.json new file mode 100644 index 000000000..c587d53fe --- /dev/null +++ b/hifi-content/howell/Prototypes/JAT_test/config.json @@ -0,0 +1,27 @@ +{ + "avatars": [ + { + "name": "Andy1", + "url": "https://raw.githubusercontent.com/AndySeattle/Avatar/master/office_zombie_alive/office_zombie_alive.fst" + }, + { + "name": "Vacation", + "url": "https://raw.githubusercontent.com/AndySeattle/Avatar/master/Zombie_on_vacation/zombie_on_vacation_hifi.fst" + }, + { + "name": "Ice Hero", + "url": "http://mpassets.highfidelity.com/e238153a-21f4-4eba-8ab5-c6b10a0eb967-v1/avatar.fst" + }, + { + "name": "Ice Hero2", + "url": "http://mpassets.highfidelity.com/e238153a-21f4-4eba-8ab5-c6b10a0eb967-v1/avatar.fst" + }, + { + "name": "ice hero 3", + "url": http://mpassets.highfidelity.com/e238153a-21f4-4eba-8ab5-c6b10a0eb967-v1/avatar.fst" + } + ], + "screenleapURL": "<URL to Screenleap associated with the Web Overlay that shows up in front of JAT>", + "controlsMessageChannel": "<Message channel used for presentation controls>", + "statusMessageChannel": "<Message channel used for changing presentation status text>" +} \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/andy_bot_bingos.js b/hifi-content/howell/Prototypes/andy_bot_bingos.js new file mode 100644 index 000000000..6a435366d --- /dev/null +++ b/hifi-content/howell/Prototypes/andy_bot_bingos.js @@ -0,0 +1,125 @@ +randFloat = function(low, high) { + return low + Math.random() * (high - low); +} + +var baseURL = "https://hifi-content.s3.amazonaws.com/milad/ROLC/Organize/Projects/Testing/Flow/out/hfr/"; + +// Link to get the urls from +var GOOGLE_SHEET_URL = "https://script.googleusercontent.com/a/macros/highfidelity.io/echo?user_content_key=z30W_Z9rqfb41pGEoxCkUM9yv8ZN8mxWuMyDWUHroj3cJ65OTSWNE_Zq7wvrTybnnFtRp6azMkya2K4Hj_UvG2HA9j2tP4Hjm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_nRPgeZU6HP_Ok_bZ6q4uc2IEwUGUhs3tubd_SaoYEJGc6Y4WQVrmGLClD6RzMAfZPxqtsdMQ32tpzl66ygAELl7JpluoKw78VudcD_Dja5DuJzk35EV1vQ&lib=MzB5vcFo1OT_VNOUwG7287OYoCQvnAuFY"; +var rand = 10000; +var min = 2000; +var timeoutPeriod = Math.floor(Math.random()*rand)+min; + +var sheetXHR; +Script.setTimeout(function(){ + //console.log("about to run XHR"); + sheetXHR = new XHR(GOOGLE_SHEET_URL, sheetSuccess, sheetFailure); + +}, timeoutPeriod); +var TABLE = []; +var TOTAL_TO_GRAB = 100; + +function XHR(url, successCb, failureCb, TIMEOUT) { + //print("XHR: request url = " + url); + var self = this; + this.url = url; + this.successCb = successCb; + this.failureCb = failureCb; + this.req = new XMLHttpRequest(); + this.req.open("GET", url, true); + this.req.timeout = TIMEOUT; + this.req.ontimeout = function () { + if (self.failureCb) { + self.failureCb(0, "timeout"); + } + }; + this.req.onreadystatechange = function () { + if (self.req.readyState === self.req.DONE) { + if (self.req.status === 200 || self.req.status === 203) { + if (self.successCb) { + self.successCb(self.req.responseText); + } + } else { + if (self.failureCb) { + self.failureCb(self.req.status, "done"); + } + } + } + }; + this.req.send(); +} + +function baseName(str) { + var base = new String(str).substring(str.lastIndexOf('/') + 1); + if (base.lastIndexOf(".") !== -1) { + base = base.substring(0, base.lastIndexOf(".")); + } + return base; +} + +function sheetFailure(status, reason) { + //console.log("sheetFailure status code = " + status + ", reason = " + reason); +} + +function sheetSuccess(response) { + //console.log("sheetSuccess status, = "); + TABLE = JSON.parse(response); + TABLE.shift(); // strip off the header row. + for (var i = 0; i < TOTAL_TO_GRAB; i++){ + TABLE.map(function(recording){ + return baseName(TABLE[i].avatar_HFR); + }) + } + + var randomIndex = Math.floor((Math.random() * TABLE.length) % TABLE.length); + var RECORDING_URL = TABLE[randomIndex].avatar_HFR; + + var LOCATIONS_ARRAY = [{ min_x: -88, max_x: -66, y: -21, min_z: 2.8, max_z: 10 }]; + + var LOCATION_PARAMS = LOCATIONS_ARRAY[Math.floor(Math.random() * LOCATIONS_ARRAY.length)]; + + var LOCATION = { x: randFloat(LOCATION_PARAMS.min_x, LOCATION_PARAMS.max_x), y: LOCATION_PARAMS.y, z: randFloat(LOCATION_PARAMS.min_z, LOCATION_PARAMS.max_z) }; + + //Vec3.print("RANDOM LOCATION SELECTED:", LOCATION); + + // Disable the privacy bubble + Users.disableIgnoreRadius(); + + // Set position here if playFromCurrentLocation is true + Avatar.position = LOCATION; + Avatar.orientation = Quat.fromPitchYawRollDegrees(0, randFloat(0, 360), 0); + Avatar.scale = 1.0; + Agent.isAvatar = true; + + Recording.loadRecording(RECORDING_URL, function(success) { + if (success) { + Script.update.connect(update); + } else { + // print("Failed to load recording from " + RECORDING_URL); + } + }); +} + +count = 300; // Randomly wait some period of time before starting the recording +function update(event) { + if (count > 0) { + count--; + return; + } + + if (count == 0) { + Recording.setPlayFromCurrentLocation(true); + Recording.setPlayerLoop(true); + Recording.startPlaying(); + //Vec3.print("Playing from ", Avatar.position); + count--; + } + + EntityViewer.setPosition(Avatar.position); + EntityViewer.setOrientation(Avatar.orientation); + EntityViewer.queryOctree(); + + if (!Recording.isPlaying()) { + Script.update.disconnect(update); + } +} \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/andy_bots.js b/hifi-content/howell/Prototypes/andy_bots.js new file mode 100644 index 000000000..4d0200259 --- /dev/null +++ b/hifi-content/howell/Prototypes/andy_bots.js @@ -0,0 +1,125 @@ +randFloat = function(low, high) { + return low + Math.random() * (high - low); +} + +var baseURL = "https://hifi-content.s3.amazonaws.com/milad/ROLC/Organize/Projects/Testing/Flow/out/hfr/"; + +// Link to get the urls from +var GOOGLE_SHEET_URL = "https://script.googleusercontent.com/a/macros/highfidelity.io/echo?user_content_key=z30W_Z9rqfb41pGEoxCkUM9yv8ZN8mxWuMyDWUHroj3cJ65OTSWNE_Zq7wvrTybnnFtRp6azMkya2K4Hj_UvG2HA9j2tP4Hjm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_nRPgeZU6HP_Ok_bZ6q4uc2IEwUGUhs3tubd_SaoYEJGc6Y4WQVrmGLClD6RzMAfZPxqtsdMQ32tpzl66ygAELl7JpluoKw78VudcD_Dja5DuJzk35EV1vQ&lib=MzB5vcFo1OT_VNOUwG7287OYoCQvnAuFY"; +var rand = 10000; +var min = 2000; +var timeoutPeriod = Math.floor(Math.random()*rand)+min; + +var sheetXHR; +Script.setTimeout(function(){ + //console.log("about to run XHR"); + sheetXHR = new XHR(GOOGLE_SHEET_URL, sheetSuccess, sheetFailure); + +}, timeoutPeriod); +var TABLE = []; +var TOTAL_TO_GRAB = 100; + +function XHR(url, successCb, failureCb, TIMEOUT) { + //print("XHR: request url = " + url); + var self = this; + this.url = url; + this.successCb = successCb; + this.failureCb = failureCb; + this.req = new XMLHttpRequest(); + this.req.open("GET", url, true); + this.req.timeout = TIMEOUT; + this.req.ontimeout = function () { + if (self.failureCb) { + self.failureCb(0, "timeout"); + } + }; + this.req.onreadystatechange = function () { + if (self.req.readyState === self.req.DONE) { + if (self.req.status === 200 || self.req.status === 203) { + if (self.successCb) { + self.successCb(self.req.responseText); + } + } else { + if (self.failureCb) { + self.failureCb(self.req.status, "done"); + } + } + } + }; + this.req.send(); +} + +function baseName(str) { + var base = new String(str).substring(str.lastIndexOf('/') + 1); + if (base.lastIndexOf(".") !== -1) { + base = base.substring(0, base.lastIndexOf(".")); + } + return base; +} + +function sheetFailure(status, reason) { + //console.log("sheetFailure status code = " + status + ", reason = " + reason); +} + +function sheetSuccess(response) { + //console.log("sheetSuccess status, = "); + TABLE = JSON.parse(response); + TABLE.shift(); // strip off the header row. + for (var i = 0; i < TOTAL_TO_GRAB; i++){ + TABLE.map(function(recording){ + return baseName(TABLE[i].avatar_HFR); + }) + } + + var randomIndex = Math.floor((Math.random() * TABLE.length) % TABLE.length); + var RECORDING_URL = TABLE[randomIndex].avatar_HFR; + + var LOCATIONS_ARRAY = [{ min_x: -6, max_x: 21, y: -12, min_z: -57, max_z: -54 }]; + + var LOCATION_PARAMS = LOCATIONS_ARRAY[Math.floor(Math.random() * LOCATIONS_ARRAY.length)]; + + var LOCATION = { x: randFloat(LOCATION_PARAMS.min_x, LOCATION_PARAMS.max_x), y: LOCATION_PARAMS.y, z: randFloat(LOCATION_PARAMS.min_z, LOCATION_PARAMS.max_z) }; + + //Vec3.print("RANDOM LOCATION SELECTED:", LOCATION); + + // Disable the privacy bubble + Users.disableIgnoreRadius(); + + // Set position here if playFromCurrentLocation is true + Avatar.position = LOCATION; + Avatar.orientation = Quat.fromPitchYawRollDegrees(0, randFloat(0, 360), 0); + Avatar.scale = 1.0; + Agent.isAvatar = true; + + Recording.loadRecording(RECORDING_URL, function(success) { + if (success) { + Script.update.connect(update); + } else { + // print("Failed to load recording from " + RECORDING_URL); + } + }); +} + +count = 300; // Randomly wait some period of time before starting the recording +function update(event) { + if (count > 0) { + count--; + return; + } + + if (count == 0) { + Recording.setPlayFromCurrentLocation(true); + Recording.setPlayerLoop(true); + Recording.startPlaying(); + //Vec3.print("Playing from ", Avatar.position); + count--; + } + + EntityViewer.setPosition(Avatar.position); + EntityViewer.setOrientation(Avatar.orientation); + EntityViewer.queryOctree(); + + if (!Recording.isPlaying()) { + Script.update.disconnect(update); + } +} \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/andy_bots_futvrelands.js b/hifi-content/howell/Prototypes/andy_bots_futvrelands.js new file mode 100644 index 000000000..4fb074a09 --- /dev/null +++ b/hifi-content/howell/Prototypes/andy_bots_futvrelands.js @@ -0,0 +1,203 @@ +// +// BetterClientSimulationBotFromRecording.js +// examples +// +// Created by Brad Hefta-Gaub on 2/6/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 +// + + +var WANT_DEBUGGING = false; + +randFloat = function(low, high) { + return low + Math.random() * (high - low); +} + +var MESSAGE_CHANNEL = "TriviaChannel"; + +var AVATARS_ARRAY = [ + "http://mpassets.highfidelity.com/0c2c264b-2fd2-46a4-bf80-de681881f66b-v1/F_MotRac.fst", + "http://mpassets.highfidelity.com/bd80a6d7-7173-489e-87c6-f7ee56e65530-v1/M_RetFut.fst", + "http://mpassets.highfidelity.com/47c8d706-d486-4c2d-afcc-70d4e1e25117-v1/M_RetSpaSuit.fst", + "http://mpassets.highfidelity.com/548d0792-0bac-4933-bbfc-57d71912d77e-v1/M_OutMer.fst", + "http://mpassets.highfidelity.com/13277c09-892f-4a5e-b9a5-8994a37d68bf-v1/F_WasWar.fst", + "http://mpassets.highfidelity.com/2d384111-0f0e-42e2-b800-66bfcab4aefb-v1/F_VooQue.fst", + "http://mpassets.highfidelity.com/57e4d1cd-9f52-4c95-9051-326f9bb114ea-v1/F_SteAvi.fst", + "http://mpassets.highfidelity.com/da2ad4cd-47d4-41da-b764-41f39ff77e30-v1/F_JerGir.fst", + "http://mpassets.highfidelity.com/96c747ab-f71b-44ee-8eb9-d19fc9593dda-v1/F_CatBur.fst", + "http://mpassets.highfidelity.com/ede82c38-c66e-4f67-9e0b-0bb0782db18f-v1/M_WesOut.fst", + "http://mpassets.highfidelity.com/8872ae86-a763-4db3-8373-d27514c1481e-v1/M_VinAvi.fst", + "http://mpassets.highfidelity.com/faf505f1-4fd1-4ed2-8909-816af246c48f-v1/M_VicGen.fst", + "http://mpassets.highfidelity.com/d807a7d2-5122-4436-a6f9-3173c94d1c49-v1/M_SuaGen.fst", + "http://mpassets.highfidelity.com/1dd41735-06f4-45a3-9ec0-d05215ace77b-v1/M_MarSen.fst", + "http://mpassets.highfidelity.com/2cad3894-8ab3-4ba5-a723-0234f93fbd6a-v1/M_BowBea.fst", + "http://mpassets.highfidelity.com/cf0eb1be-9ec7-4756-8eaf-ac8f3ec09eba-v1/F_ClaDef.fst", + "http://mpassets.highfidelity.com/0cedeca3-c1a4-4be9-9fd5-dad716afcc7e-v1/F_Cyria.fst", + "http://mpassets.highfidelity.com/dc55803b-9215-47dd-9408-eb835dac4082-v1/F_ParGir.fst", + "http://mpassets.highfidelity.com/775a8fb3-cfe7-494d-b603-a0a2d6910e55-v1/F_VinCov.fst", + "http://mpassets.highfidelity.com/eba0d8f8-aa72-4a6b-ab64-4d3fd4695b20-v1/F_VogHei.fst", + "http://mpassets.highfidelity.com/4f400c78-38f9-42af-b03b-11b5451d41b9-v1/M_MidRog.fst", + "http://mpassets.highfidelity.com/ad774d79-13f1-46e2-87c9-de49a261b264-v1/F_GunSli.fst", + "http://mpassets.highfidelity.com/5acbaefa-5455-49a2-8d40-89d12aa393ca-v1/M_KniWol.fst", + "http://mpassets.highfidelity.com/aaa1b0a8-3e1b-492a-9aee-600e5dc907db-v1/F_RetSciSuit.fst", + "http://mpassets.highfidelity.com/d8da10b6-25c1-40e2-9a66-369316c722d7-v1/F_AniSuit.fst", + "http://mpassets.highfidelity.com/f3fbb9f4-e159-49ed-ac32-03af9056b17e-v1/matthew.fst", + "http://mpassets.highfidelity.com/0c954ba0-4d87-4353-b65e-c45509f85658-v1/priscilla.fst", + "http://mpassets.highfidelity.com/e76946cc-c272-4adf-9bb6-02cde0a4b57d-v1/9e8c5c42a0cbd436962d6bd36f032ab3.fst", + "http://mpassets.highfidelity.com/72e083ee-194d-4113-9c61-0591d8257493-v1/skeleton_Rigged.fst", + "http://mpassets.highfidelity.com/f14bf7c9-49a1-4249-988a-0a577ed78957-v1/beingOfLight.fst", + "http://mpassets.highfidelity.com/1b7e1e7c-6c0b-4f20-9cd0-1d5ccedae620-v1/bb64e937acf86447f6829767e958073c.fst", + "http://mpassets.highfidelity.com/67d7c7aa-c300-4d03-85f4-86480130eaa5-v1/F_StarCrew.fst", + "http://mpassets.highfidelity.com/d293ef06-c659-467a-9288-c3cbaff0372a-v1/arya_avatar.fst", + "http://mpassets.highfidelity.com/faf249d5-12a8-48e2-a08e-fb0c33087011-v1/F_Ranger.fst", + "http://mpassets.highfidelity.com/b4502145-15eb-4023-b7d6-a81c5cbf6abf-v1/F_FitTra.fst", + "http://mpassets.highfidelity.com/548d0792-0bac-4933-bbfc-57d71912d77e-v1/M_OutMer.fst", + "http://mpassets.highfidelity.com/caa61e5d-5629-4165-81d8-6a7eb55e942d-v1/F_DeaSur.fst", + "http://mpassets.highfidelity.com/2cad3894-8ab3-4ba5-a723-0234f93fbd6a-v1/M_BowBea.fst", + "http://mpassets.highfidelity.com/fd4fa45a-9d2a-463e-a484-f9d1b3bba724-v1/M_BeaWar.fst", + "http://mpassets.highfidelity.com/367a5b60-8a92-4d56-a152-a00f3086f02b-v1/M_Espio.fst", + "http://mpassets.highfidelity.com/ab466729-31da-4b4c-a33c-366f7c1d38e5-v1/M_MMAFig.fst", + "http://mpassets.highfidelity.com/b0795a0c-493d-4abd-b4cc-5f32e6d6df46-v1/M_SalMer.fst", + "http://mpassets.highfidelity.com/0a1d44bf-a988-4199-b29e-a532ab85a2e8-v1/M_StaShi.fst", + "http://mpassets.highfidelity.com/d807a7d2-5122-4436-a6f9-3173c94d1c49-v1/M_SuaGen.fst", + "http://mpassets.highfidelity.com/cb20212c-36f2-4d41-bdad-132361ca6ff4-v1/M_TreTee.fst", + "http://mpassets.highfidelity.com/830988dc-619a-4e88-96e1-a19fa0aaa30f-v1/M_UrbEnf.fst", + "http://mpassets.highfidelity.com/faf505f1-4fd1-4ed2-8909-816af246c48f-v1/M_VicGen.fst", + "http://mpassets.highfidelity.com/883ac86f-dd29-4676-8bda-7dd52fb6465f-v1/M_WasWan.fst", + "http://mpassets.highfidelity.com/ede82c38-c66e-4f67-9e0b-0bb0782db18f-v1/M_WesOut.fst", + "http://mpassets.highfidelity.com/04c9a1e9-0390-4a7f-b6c6-5f135c19e3fb-v1/F_ArmTro.fst", + "http://mpassets.highfidelity.com/e863348f-a777-4f36-86e6-af6e65ffa161-v1/F_BloSam.fst", + "http://mpassets.highfidelity.com/cf0eb1be-9ec7-4756-8eaf-ac8f3ec09eba-v1/F_ClaDef.fst", + "http://mpassets.highfidelity.com/0cedeca3-c1a4-4be9-9fd5-dad716afcc7e-v1/F_Cyria.fst", + "http://mpassets.highfidelity.com/da2ad4cd-47d4-41da-b764-41f39ff77e30-v1/F_JerGir.fst", + "http://mpassets.highfidelity.com/534d42f8-ec13-4145-929f-5c8facac2fb7-v1/F_LegFig.fst", + "http://mpassets.highfidelity.com/dc55803b-9215-47dd-9408-eb835dac4082-v1/F_ParGir.fst", + "http://mpassets.highfidelity.com/f823e831-d8c4-4191-a3bd-427e406e69f9-v1/F_Shinjuku.fst", + "http://mpassets.highfidelity.com/eba0d8f8-aa72-4a6b-ab64-4d3fd4695b20-v1/F_VogHei.fst", + "http://mpassets.highfidelity.com/13277c09-892f-4a5e-b9a5-8994a37d68bf-v1/F_WasWar.fst", + "http://mpassets.highfidelity.com/9b589fbb-59e4-47a9-8b3f-bf8d3a0bd1d8-v1/M_LawSur.fst", + "http://mpassets.highfidelity.com/4f400c78-38f9-42af-b03b-11b5451d41b9-v1/M_MidRog.fst", + "http://mpassets.highfidelity.com/c90d755d-0456-48fd-b98c-09c4d85cd481-v1/M_MouOff.fst", + "http://mpassets.highfidelity.com/c2ed3b9a-b3a9-4424-9fd2-8a798209f32b-v1/M_PerTra.fst", + "http://mpassets.highfidelity.com/c48928ac-7657-41f4-bbdc-9b47385736ab-v1/M_SpaMar.fst", + "http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst", + "http://mpassets.highfidelity.com/c85c497d-c87b-42b1-9bbf-5405e05a0ad3-v1/M_ArmSol.fst", + "http://mpassets.highfidelity.com/1dd41735-06f4-45a3-9ec0-d05215ace77b-v1/M_MarSen.fst", + "http://mpassets.highfidelity.com/bd80a6d7-7173-489e-87c6-f7ee56e65530-v1/M_RetFut.fst", + "http://mpassets.highfidelity.com/8872ae86-a763-4db3-8373-d27514c1481e-v1/M_VinAvi.fst", + "http://mpassets.highfidelity.com/f798d926-9a9e-481a-b298-af0e45451252-v1/F_Assassin.fst", + "http://mpassets.highfidelity.com/ad774d79-13f1-46e2-87c9-de49a261b264-v1/F_GunSli.fst", + "http://mpassets.highfidelity.com/aaa1b0a8-3e1b-492a-9aee-600e5dc907db-v1/F_RetSciSuit.fst" + ]; + + +var AVATAR_URL = AVATARS_ARRAY[Math.floor(Math.random() * AVATARS_ARRAY.length)]; +print("RANDOM AVATAR SELECTED:" + AVATAR_URL); + +var RECORDINGS_ARRAY = [ + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting6.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/waiting10.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot1.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot2.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot3.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot4.hfr" + ]; + +var RECORDING_URL = RECORDINGS_ARRAY[Math.floor(Math.random() * RECORDINGS_ARRAY.length)]; +print("RANDOM RECORDING SELECTED:" + RECORDING_URL); + +// not quite what I want... +var LOCATIONS_ARRAY = [ + { min_x: -91, max_x: -40, y: -19.2, min_z: -1.8, max_z: 90 } +]; + +var LOCATION_PARAMS = LOCATIONS_ARRAY[Math.floor(Math.random() * LOCATIONS_ARRAY.length)]; + +var LOCATION = { x: randFloat(LOCATION_PARAMS.min_x, LOCATION_PARAMS.max_x), y: LOCATION_PARAMS.y, z: randFloat(LOCATION_PARAMS.min_z, LOCATION_PARAMS.max_z) }; + +Vec3.print("RANDOM LOCATION SELECTED:", LOCATION); + +var playFromCurrentLocation = true; +var loop = true; + +// Disable the privacy bubble +Users.disableIgnoreRadius(); + +// Set position here if playFromCurrentLocation is true +Avatar.position = LOCATION; +Avatar.orientation = Quat.fromPitchYawRollDegrees(1, 0, 0); +Avatar.scale = 1.0; +Agent.isAvatar = true; + +// make the agent "listen" to the audio stream to cause additional audio-mixer load, technically this isn't needed when you're playing a recording +// but if you switch to a non-recording bot, you will need this, so we can leave this. +Agent.isListeningToAudioStream = true; +Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored + + +function messageLog(channel, sender, message) { + if (channel === MESSAGE_CHANNEL) { + print ("AC Bot at position: " + JSON.stringify(Avatar.position) + " received message on " + MESSAGE_CHANNEL); + } +} + +Recording.loadRecording(RECORDING_URL, function(success) { + if (success) { + Script.update.connect(update); + Messages.subscribe(MESSAGE_CHANNEL); + Messages.messageReceived.connect(messageLog); + } else { + print("Failed to load recording from " + RECORDING_URL); + } +}); + + +count = 300; // This is necessary to wait for the audio mixer to connect +function update(event) { + if (count > 0) { + count--; + return; + } + if (count == 0) { + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerLoop(loop); + Recording.setPlayerUseDisplayName(true); + Recording.setPlayerUseAttachments(true); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(false); // FIXME - this would allow you to override the recording avatar, but that's not currently working + Recording.startPlaying(); + Vec3.print("Playing from ", Avatar.position); + count--; + } else if (WANT_DEBUGGING) { + count = 100; + Vec3.print("Avatar at: ", Avatar.position); + Quat.print("Avatar head orientation: ", Avatar.headOrientation); + print("outbound:" + +" GP: " + Avatar.getDataRate("globalPositionOutbound").toFixed(2) + "\n" + +" LP: " + Avatar.getDataRate("localPositionOutbound").toFixed(2) + "\n" + +" BB: " + Avatar.getDataRate("avatarBoundingBoxOutbound").toFixed(2) + "\n" + +" AO: " + Avatar.getDataRate("avatarOrientationOutbound").toFixed(2) + "\n" + +" AS: " + Avatar.getDataRate("avatarScaleOutbound").toFixed(2) + "\n" + +" LA: " + Avatar.getDataRate("lookAtPositionOutbound").toFixed(2) + "\n" + +" AL: " + Avatar.getDataRate("audioLoudnessOutbound").toFixed(2) + "\n" + +" SW: " + Avatar.getDataRate("sensorToWorkMatrixOutbound").toFixed(2) + "\n" + +" AF: " + Avatar.getDataRate("additionalFlagsOutbound").toFixed(2) + "\n" + +" PI: " + Avatar.getDataRate("parentInfoOutbound").toFixed(2) + "\n" + +" FT: " + Avatar.getDataRate("faceTrackerOutbound").toFixed(2) + "\n" + +" JD: " + Avatar.getDataRate("jointDataOutbound").toFixed(2)); + } + + if (!Recording.isPlaying()) { + Script.update.disconnect(update); + Messages.unsubscribe(MESSAGE_CHANNEL); + Messages.messageReceived.disconnect(messageLog); + } +} + +Script.scriptEnding.connect(function(){ + Messages.unsubscribe(MESSAGE_CHANNEL); +}); \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/best_game.jpg b/hifi-content/howell/Prototypes/best_game.jpg new file mode 100644 index 000000000..21de3c1b5 --- /dev/null +++ b/hifi-content/howell/Prototypes/best_game.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5db32657baee0bfc6ccae71cfb87f81a5f9b40037bcb9d237543406a3fc5b517 +size 95702 diff --git a/hifi-content/howell/Prototypes/bot_player_content_v4/assignmentClientManager_andy_test.js b/hifi-content/howell/Prototypes/bot_player_content_v4/assignmentClientManager_andy_test.js new file mode 100644 index 000000000..ff04f194f --- /dev/null +++ b/hifi-content/howell/Prototypes/bot_player_content_v4/assignmentClientManager_andy_test.js @@ -0,0 +1,247 @@ +"use strict"; + +// +// Bot Player +// assignmentClientManager.js +// Created by Milad Nazeri on 2019-06-06 +// Copyright 2019 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 +// + + +(function() { + + // ************************************* + // START UTILITY FUNCTIONS + // ************************************* + // #region UTILITY FUNCTIONS + + + // Start playing sequence to fill players with bots + var AC_AVAILABILITY_CHECK_MS = 1000; + function startSequence() { + // Check to see how many bots are needed + if (botCount >= botsFound + 1) { + return; + } + + if (botCount < availableAssignmentClientPlayers.length) { + var player = availableAssignmentClientPlayers[botCount]; + player.play(); + botCount++; + + if (botCount >= botsFound + 1) { + return; + } + } + + Script.setTimeout(function() { + startSequence(); + }, AC_AVAILABILITY_CHECK_MS); + } + + + // Searching through the s3 bucket to grab which recordings are valid and stop as soon as we get an error + // Synchronous version of require + var BASE_PATH = "https://hifi-content.s3.amazonaws.com/howell/bots_new/"; + var MAX_BOTS_TO_TRY = 100; + var requestSync = Script.require("./requestSync.js").request; + var botsFound = 0; + function populateRecordingList(){ + for (var i = 1; i < MAX_BOTS_TO_TRY; i++) { + var botRecordingFound = true; + var currentBotUrl = BASE_PATH + "AVATAR_TEST" + i + ".hfr"; + requestSync(currentBotUrl, function(error){ + if (error) { + botRecordingFound = false; + } else { + botsFound++; + botList.push(currentBotUrl); + } + }); + if (!botRecordingFound) { + break; + } + } + } + + + // #endregion + // ************************************* + // END UTILITY FUNCTIONS + // ************************************* + + // ************************************* + // START CONSTS_AND_VARS + // ************************************* + // #region CONSTS_AND_VARS + + + // The Assignment Client channel + var ASSIGNMENT_MANAGER_CHANNEL = "ASSIGNMENT_MANAGER_CHANNEL"; + var ASSIGNMENT_CLIENT_MESSANGER_CHANNEL = "ASSIGNMENT_CLIENT_MESSANGER_CHANNEL"; + + // Array of the assignment client players and their assignment client player object + var availableAssignmentClientPlayers = []; + + // Current playing bot count we are at + var botCount = 0; + + // Current registered bount count + var botsRegisteredCount = 0; + + // Array of the recordings found + var botList = []; + + + // #endregion + // ************************************* + // END CONSTS_AND_VARS + // ************************************* + + // ************************************* + // START ASSIGNMENT_CLIENT_PLAYER + // ************************************* + // #region ASSIGNMENT_CLIENT_PLAYER + + + // Individual AssignmentClientPlayerObject + function AssignmentClientPlayerObject(uuid, fileToPlay, position, volume) { + this.uuid = uuid; + this.fileToPlay = fileToPlay; + } + + + // Play the current clip + function play() { + Messages.sendMessage(ASSIGNMENT_MANAGER_CHANNEL, JSON.stringify({ + action: "PLAY", + fileToPlay: this.fileToPlay, + uuid: this.uuid + })); + } + + + // Stop the current clip + function stop() { + Messages.sendMessage(ASSIGNMENT_MANAGER_CHANNEL, JSON.stringify({ + action: "STOP", + uuid: this.uuid + })); + } + + + AssignmentClientPlayerObject.prototype = { + play: play, + stop: stop + }; + + + // #endregion + // ************************************* + // END ASSIGNMENT_CLIENT_PLAYER + // ************************************* + + // ************************************* + // START MESSAGES + // ************************************* + // #region MESSAGES + + + // Handle Messages received + function onMangerChannelMessageReceived(channel, message, sender) { + if (channel !== ASSIGNMENT_MANAGER_CHANNEL || sender === Agent.sessionUUID) { + return; + } + + try { + message = JSON.parse(message); + } catch (error) { + console.log("invalid object"); + console.log("MESSAGE:", message); + return; + } + + switch (message.action) { + case "REGISTER_ME": + var fileName = botList[botsRegisteredCount]; + availableAssignmentClientPlayers.push( + new AssignmentClientPlayerObject(message.uuid, fileName)); + botsRegisteredCount++; + var messageToSend = JSON.stringify({ + action: "AC_AVAILABLE_UPDATE", + newAvailableACs: availableAssignmentClientPlayers.length + }); + Messages.sendMessage(ASSIGNMENT_CLIENT_MESSANGER_CHANNEL, messageToSend); + break; + case "ARE_YOU_THERE_MANAGER_ITS_ME_BOT": + Messages.sendMessage(ASSIGNMENT_MANAGER_CHANNEL, JSON.stringify({ + action: "REGISTER_MANAGER", + uuid: sender + })); + break; + default: + console.log("unrecognized action in assignmentClientManger.js"); + break; + } + } + + + // #endregion + // ************************************* + // END MESSAGES + // ************************************* + + // ************************************* + // START MAIN + // ************************************* + // #region MAIN + + + // Startup for the manager when it comes online + function startUp() { + Messages.subscribe(ASSIGNMENT_MANAGER_CHANNEL); + Messages.subscribe(ASSIGNMENT_CLIENT_MESSANGER_CHANNEL); + Messages.messageReceived.connect(onMangerChannelMessageReceived); + Script.scriptEnding.connect(onEnding); + populateRecordingList(); + startSequence(); + } + + startUp(); + + + // #endregion + // ************************************* + // END MAIN + // ************************************* + + // ************************************* + // START CLEANUP + // ************************************* + // #region CLEANUP + + + // Cleanup the manager and it's messages + function onEnding() { + Messages.messageReceived.disconnect(onMangerChannelMessageReceived); + var messageToSend = JSON.stringify({ + action: "GET_MANAGER_STATUS", + newAvailableACs: 0, + isPlaying: false, + closeTablet: true + }); + Messages.sendMessage(ASSIGNMENT_CLIENT_MESSANGER_CHANNEL, messageToSend); + Messages.unsubscribe(ASSIGNMENT_MANAGER_CHANNEL); + Messages.unsubscribe(ASSIGNMENT_CLIENT_MESSANGER_CHANNEL); + } + + + // #endregion + // ************************************* + // END CLEANUP + // ************************************* + +})(); diff --git a/hifi-content/howell/Prototypes/bouncer.js b/hifi-content/howell/Prototypes/bouncer.js new file mode 100644 index 000000000..ce54d5497 --- /dev/null +++ b/hifi-content/howell/Prototypes/bouncer.js @@ -0,0 +1,270 @@ +// +// ZoneScript.js +// +// This script serves as a virtual bouncer depending on username or whether or not a client can validate +// ownership of a particular specified avatar entity. Can one or all three methods: hardcoded list in APPROVED_USERNAMES, +// inside entity userData username list, and/or verifying an wearable marketplace entity through it's ID. +// +// Copyright 2017 High Fidelity, Inc. +// +// Set Up: +// 1. Add below userData object to zone entity userData +// 1. Fill in rejectTeleportLocation, example "/13.9828,-10.5277,0.0609192/0,0.460983,0,0.887409" +// 2. Optional: add marketplaceID of the item to verify +// 3. Optional: (can update while script is running): each username to add to whitelist +// 2. Add approved users to APPROVED_USERNAMES below, keep blank if not using +// 3. Add script to zone entity +// 4. Update userData at anytime to add more to usernames your whitelist +// +// Add this to the zone userData : +// { +// "whitelist" : { +// "rejectTeleportLocation" : "<<INSERT HIFI ADDRESS>>" +// "marketplaceID" : "<<INSERT MARKETPLACE ITEM ID>>", +// "usernames" : [""] +// }, +// "grabbableKey": { +// "grabbable": false +// } +// } +// +// whitelist - (required) contains variables for the zone +// rejectTeleportLocation - (required) rejected avatars are sent to these domain coordinates +// marketplaceID - (optional) marketplace item id for marketplace item verification +// usernames - (optional) array for usernames to be added while script is running +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +/* globals Entities, Wallet, Window, AccountServices */ + +(function () { + + // username lookup variables + var APPROVED_USERNAMES = []; // hardcoded + var whitelist = []; // stores lowercase usernames from APPROVED_USERNAMES + + // usernames inside userData + var _usernames; // userData names + + // marketplace lookup variables + var WEARABLE_SEARCH_RADIUS = 10; + var foundValidTestable = false; + var _foundEntityID = -1; + var _passMarketplaceID; + var _userDataProperties; + var _backupLocation; + + var _entityID; + var LOAD_TIME = 50; + var avatarCheckStep = 0; + var HALF = 0.5; + var DEBUG = false; + + var marketplaceItem = { + + verificationSuccess: function (entityID) { + if (DEBUG) { + print("You may enter - verification passed for entity: " + entityID); + } + Wallet.ownershipVerificationSuccess.disconnect(this.verificationSuccess); + Wallet.ownershipVerificationFailed.disconnect(this.verificationFailed); + }, + + verificationFailed: function (entityID) { + if (DEBUG) { + print("You may not enter - verification failed for entity: " + entityID); + } + utils.rejectTeleportAvatar(); + Wallet.ownershipVerificationSuccess.disconnect(this.verificationSuccess); + Wallet.ownershipVerificationFailed.disconnect(this.verificationFailed); + }, + + verifyAvatarOwnership: function (entityID) { + Wallet.proveAvatarEntityOwnershipVerification(entityID); + }, + searchForMatchingItem: function () { + Entities.findEntitiesByType('Model', MyAvatar.position, WEARABLE_SEARCH_RADIUS).forEach(function (entityID) { + var properties = Entities.getEntityProperties(entityID, ['marketplaceID', 'certificateID', 'parentID']); + if (properties.marketplaceID === _passMarketplaceID && properties.parentID === MyAvatar.sessionUUID) { + _foundEntityID = entityID; + foundValidTestable = true; + this.verifyAvatarOwnership(_foundEntityID); + Wallet.ownershipVerificationSuccess.connect(this.verificationSuccess); + Wallet.ownershipVerificationFailed.connect(this.verificationFailed); + } + }); + if (!foundValidTestable) { + utils.rejectTeleportAvatar(); + } + } + }; + + var avatarUserName = { + isOnWhitelist: function () { + var username = AccountServices.username.toLowerCase(); + if (whitelist.indexOf(username) >= 0) { + if (DEBUG) { + print("Username is on hardcoded whitelist"); + } + return true; + } else { + return false; + } + }, + isInUserData: function () { + var username = AccountServices.username.toLowerCase(); + + for (var i = 0; i < _usernames.length; i++) { + if (_usernames[i].toLowerCase() === username) { + if (DEBUG) { + print("Username is on userData whitelist"); + } + return true; + } + } + return false; + } + }; + + var utils = { + + updateUserData: function () { + try { + _userDataProperties = JSON.parse(Entities.getEntityProperties(_entityID, 'userData').userData); + } catch (err) { + console.error("Error parsing userData: ", err); + } + + _usernames = _userDataProperties.whitelist && _userDataProperties.whitelist.usernames || []; + }, + + rejectTeleportAvatar: function () { + if (DEBUG) { + print("Rejected from zone to: ", _backupLocation); + } + Window.location.handleLookupString(_backupLocation); + }, + + largestAxisVec: function (dimensions) { + var max = Math.max(dimensions.x, dimensions.y, dimensions.z); + return max; + }, + + isInEntity: function () { + var properties = Entities.getEntityProperties(_entityID, ["position", "dimensions", "rotation"]); + var position = properties.position; + var dimensions = properties.dimensions; + + var avatarPosition = MyAvatar.position; + var worldOffset = Vec3.subtract(avatarPosition, position); + + avatarPosition = Vec3.multiplyQbyV(Quat.inverse(properties.rotation), worldOffset); + + var minX = 0 - dimensions.x * HALF; + var maxX = 0 + dimensions.x * HALF; + var minY = 0 - dimensions.y * HALF; + var maxY = 0 + dimensions.y * HALF; + var minZ = 0 - dimensions.z * HALF; + var maxZ = 0 + dimensions.z * HALF; + + if (avatarPosition.x >= minX && avatarPosition.x <= maxX + && avatarPosition.y >= minY && avatarPosition.y <= maxY + && avatarPosition.z >= minZ && avatarPosition.z <= maxZ) { + + if (DEBUG) { + print("Avatar is inside zone"); + } + return true; + + } else { + + if (DEBUG) { + print("Avatar is NOT in zone"); + } + return false; + } + } + + }; + + var ProtectedZone = function () { + + }; + + ProtectedZone.prototype = { + + preload: function (entityID) { + _entityID = entityID; + var _this = this; + + + if (APPROVED_USERNAMES.length > 0) { + APPROVED_USERNAMES.forEach(function (username) { + whitelist.push(username.toLowerCase()); + }); + } + + utils.updateUserData(); + + Script.setTimeout(function () { + if (_userDataProperties.whitelist) { + + _passMarketplaceID = _userDataProperties.whitelist.marketplaceID || ""; + _backupLocation = _userDataProperties.whitelist.rejectTeleportLocation; + _usernames = _userDataProperties.whitelist.usernames || []; + + } + _this.insideEntityCheck(); + + }, LOAD_TIME); + + }, + insideEntityCheck: function () { + // ensures every avatar experiences the enterEntity method + var properties = Entities.getEntityProperties(_entityID, ["position", "dimensions"]); + var largestDimension = utils.largestAxisVec(properties.dimensions); + var avatarsInRange = AvatarList.getAvatarsInRange(properties.position, largestDimension).filter(function(id) { + return id === MyAvatar.sessionUUID; + }); + + if (avatarsInRange.length > 0) { + if (DEBUG) { + print("Found avatar near zone: ", avatarCheckStep); + } + // do isInZone check + if (utils.isInEntity()) { + this.enterEntity(); + } + } + }, + enterEntity: function () { + + utils.updateUserData(); + + Script.setTimeout(function () { + + var isInUserData = avatarUserName.isInUserData(); + + if (isInUserData || (APPROVED_USERNAMES.length > 0 && avatarUserName.isOnWhitelist())) { + // do nothing + } else { + // did not pass username tests + if (_passMarketplaceID) { + // if marketplaceID exists look for item + foundValidTestable = false; + marketplaceItem.searchForMatchingItem(); // will reject within function + } else { + // otherwise reject avatar + utils.rejectTeleportAvatar(); + } + } + + }, LOAD_TIME); + + } + }; + + return new ProtectedZone(); + +}); \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/crabble.png b/hifi-content/howell/Prototypes/crabble.png new file mode 100644 index 000000000..b41fe4da9 --- /dev/null +++ b/hifi-content/howell/Prototypes/crabble.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96d1d7254d45ddbaf8aa8dc1e07c2301a98295a74a6fb797c344b6fb69f82fb0 +size 9172 diff --git a/hifi-content/howell/Prototypes/dog_skull/dogskull.mtl b/hifi-content/howell/Prototypes/dog_skull/dogskull.mtl new file mode 100644 index 000000000..e32b28f43 --- /dev/null +++ b/hifi-content/howell/Prototypes/dog_skull/dogskull.mtl @@ -0,0 +1,14 @@ +# +# Wavefront material file +# Created in RealityCapture v1.0.3.4658 +# www.capturingreality.com +# + + +newmtl dogskull_Material_u1_v1 +Ka 1 1 1 +Kd 1 1 1 +d 1 +Ns 0 +illum 1 +map_Kd dogskull_u1_v1.jpg diff --git a/hifi-content/howell/Prototypes/dog_skull/dogskull.obj b/hifi-content/howell/Prototypes/dog_skull/dogskull.obj new file mode 100644 index 000000000..aac6fb09b --- /dev/null +++ b/hifi-content/howell/Prototypes/dog_skull/dogskull.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e32bd05e62eb3e4b428f611364117ecffcfc60beec2e139155e226730f124e0 +size 5187505 diff --git a/hifi-content/howell/Prototypes/dog_skull/dogskull_u1_v1.jpg b/hifi-content/howell/Prototypes/dog_skull/dogskull_u1_v1.jpg new file mode 100644 index 000000000..75674ebed --- /dev/null +++ b/hifi-content/howell/Prototypes/dog_skull/dogskull_u1_v1.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be3619b68560da8c9ecb4680014ca2024c1a4815245b04a9cd9df939bba5f084 +size 566510 diff --git a/hifi-content/howell/Prototypes/glasses.jpg b/hifi-content/howell/Prototypes/glasses.jpg new file mode 100644 index 000000000..26aa3eca1 --- /dev/null +++ b/hifi-content/howell/Prototypes/glasses.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:893bbc9eb8ec5296bc168f28e9e73717fcbe5641c59fcbba3783411dad0dc7d8 +size 111129 diff --git a/hifi-content/howell/Prototypes/jat_test2/JATScritp.js b/hifi-content/howell/Prototypes/jat_test2/JATScritp.js new file mode 120000 index 000000000..4a027c37a --- /dev/null +++ b/hifi-content/howell/Prototypes/jat_test2/JATScritp.js @@ -0,0 +1 @@ +../JAT_test/JATScritp.js \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/jat_test2/config.json b/hifi-content/howell/Prototypes/jat_test2/config.json new file mode 120000 index 000000000..d476b91f5 --- /dev/null +++ b/hifi-content/howell/Prototypes/jat_test2/config.json @@ -0,0 +1 @@ +../JAT_test/config.json \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/jat_test3/JATScritp.js b/hifi-content/howell/Prototypes/jat_test3/JATScritp.js new file mode 120000 index 000000000..4a027c37a --- /dev/null +++ b/hifi-content/howell/Prototypes/jat_test3/JATScritp.js @@ -0,0 +1 @@ +../JAT_test/JATScritp.js \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/jat_test3/config.json b/hifi-content/howell/Prototypes/jat_test3/config.json new file mode 100644 index 000000000..bab4ef25a --- /dev/null +++ b/hifi-content/howell/Prototypes/jat_test3/config.json @@ -0,0 +1,27 @@ +{ + "avatars": [ + { + "name": "Andy1", + "url": "https://raw.githubusercontent.com/AndySeattle/Avatar/master/office_zombie_alive/office_zombie_alive.fst" + }, + { + "name": "Vacation", + "url": "https://raw.githubusercontent.com/AndySeattle/Avatar/master/Zombie_on_vacation/zombie_on_vacation_hifi.fst" + }, + { + "name": "Ice Hero", + "url": "http://mpassets.highfidelity.com/e238153a-21f4-4eba-8ab5-c6b10a0eb967-v1/avatar.fst" + }, + { + "name": "Ice Hero2", + "url": "http://mpassets.highfidelity.com/e238153a-21f4-4eba-8ab5-c6b10a0eb967-v1/avatar.fst" + }, + { + "name": "ice hero 3", + "url": "http://mpassets.highfidelity.com/e238153a-21f4-4eba-8ab5-c6b10a0eb967-v1/avatar.fst" + } + ], + "screenleapURL": "<URL to Screenleap associated with the Web Overlay that shows up in front of JAT>", + "controlsMessageChannel": "<Message channel used for presentation controls>", + "statusMessageChannel": "<Message channel used for changing presentation status text>" +} \ No newline at end of file diff --git a/hifi-content/howell/Prototypes/neon_snowflake.jpg b/hifi-content/howell/Prototypes/neon_snowflake.jpg new file mode 100644 index 000000000..79fa686f4 --- /dev/null +++ b/hifi-content/howell/Prototypes/neon_snowflake.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bfb883b0e50213df4c94a032ca6ec923a2a2db42f4044c64bee2391ed3bb846 +size 97273 diff --git a/hifi-content/howell/Prototypes/neonturkey.jpg b/hifi-content/howell/Prototypes/neonturkey.jpg new file mode 100644 index 000000000..09050407d --- /dev/null +++ b/hifi-content/howell/Prototypes/neonturkey.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f20e6d01aa352b271d87abc354cbd7cef04586ae1cdf4a3a096e65e22ba24a86 +size 111176 diff --git a/hifi-content/howell/Prototypes/pants.JPG b/hifi-content/howell/Prototypes/pants.JPG new file mode 100644 index 000000000..9153c3125 --- /dev/null +++ b/hifi-content/howell/Prototypes/pants.JPG @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:276cb6ffb72c6c8056293a57805083d9b7f04db9f172cf59253f301c0307d9e6 +size 57787 diff --git a/hifi-content/howell/Prototypes/pumpkins.jpg b/hifi-content/howell/Prototypes/pumpkins.jpg new file mode 100644 index 000000000..2e0032f75 --- /dev/null +++ b/hifi-content/howell/Prototypes/pumpkins.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6096a4bd8321589982b32f7d4b88ac5dea8680930d3f339f1ab414f9f68ff9a9 +size 322425 diff --git a/hifi-content/howell/Prototypes/satdium.fbx b/hifi-content/howell/Prototypes/satdium.fbx new file mode 100644 index 000000000..d0ab9de37 --- /dev/null +++ b/hifi-content/howell/Prototypes/satdium.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32b6e4ff38986bb5e00dc6308fc02df7f23e08a635929afd0798dd4ba70a2c4a +size 3316816 diff --git a/hifi-content/howell/Prototypes/shirt.jpg b/hifi-content/howell/Prototypes/shirt.jpg new file mode 100644 index 000000000..f08a2fe72 --- /dev/null +++ b/hifi-content/howell/Prototypes/shirt.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:528968504004a0c1939076b50bfaf2fb20f825d9c1b98d5f7aa96d0365f3f451 +size 78865 diff --git a/hifi-content/howell/Prototypes/snowflake.PNG b/hifi-content/howell/Prototypes/snowflake.PNG new file mode 100644 index 000000000..0d3fbb313 --- /dev/null +++ b/hifi-content/howell/Prototypes/snowflake.PNG @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f06cad98fe7c0456945ab0701f111fca696e21e359b3468b09413afec08913a +size 348816 diff --git a/hifi-content/howell/Prototypes/space.jpg b/hifi-content/howell/Prototypes/space.jpg new file mode 100644 index 000000000..f11c98346 --- /dev/null +++ b/hifi-content/howell/Prototypes/space.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68249cffab436921e5326a80e01e16b681689c8b8a44e350e89df9d5df27a174 +size 242924 diff --git a/hifi-content/howell/Prototypes/space2.jpg b/hifi-content/howell/Prototypes/space2.jpg new file mode 100644 index 000000000..35b375e15 --- /dev/null +++ b/hifi-content/howell/Prototypes/space2.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:915657c377ec8f664bcef5d0ed8344afecf7b86493a3a448d58f7201a73f0a20 +size 147379 diff --git a/hifi-content/howell/Prototypes/team_directory.PNG b/hifi-content/howell/Prototypes/team_directory.PNG new file mode 100644 index 000000000..4d0c5b2bd --- /dev/null +++ b/hifi-content/howell/Prototypes/team_directory.PNG @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9dcea6bdd128e75bb99aae1717a5b552ce68113a06f27693d95b4349d4e16e89 +size 29101 diff --git a/hifi-content/howell/Prototypes/turkeybleh.png b/hifi-content/howell/Prototypes/turkeybleh.png new file mode 100644 index 000000000..07622a8b9 --- /dev/null +++ b/hifi-content/howell/Prototypes/turkeybleh.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab45cb8a0edf4459ad856c581862b52e0e2a39d9d27cc7b87a14709743414ab6 +size 147349 diff --git a/hifi-content/howell/Prototypes/ugly_sweater.jpg b/hifi-content/howell/Prototypes/ugly_sweater.jpg new file mode 100644 index 000000000..bdf549913 --- /dev/null +++ b/hifi-content/howell/Prototypes/ugly_sweater.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5a7337f0cad399bee35ebefa412d0f8acb8cda2d5b299c6f5af5edd5f8f94fc +size 20781 diff --git a/hifi-content/howell/Prototypes/wheel_of_current_events.png b/hifi-content/howell/Prototypes/wheel_of_current_events.png new file mode 100644 index 000000000..f812cab83 --- /dev/null +++ b/hifi-content/howell/Prototypes/wheel_of_current_events.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23e76865a807aed401b0cbb61516ac94474aa6ce1fdc8b63c4f412c08125de41 +size 90689 diff --git a/hifi-content/howell/bots/AVATAR_TEST1.hfr b/hifi-content/howell/bots/AVATAR_TEST1.hfr new file mode 100644 index 000000000..f83d11201 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST1.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1c912c52b81e0c826eebf36af923f53d712a96bb160521e477b1ab2a62937c1 +size 7974898 diff --git a/hifi-content/howell/bots/AVATAR_TEST10.hfr b/hifi-content/howell/bots/AVATAR_TEST10.hfr new file mode 100644 index 000000000..73926b371 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST10.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc3513dcb18a9881d624589b2c9774d9bbf8624bd1cd8219628a77c4f3c1800a +size 1135949 diff --git a/hifi-content/howell/bots/AVATAR_TEST11.hfr b/hifi-content/howell/bots/AVATAR_TEST11.hfr new file mode 100644 index 000000000..bf5badf2d --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST11.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bd91df2847a77d64f53f8eaadb83a1554e011686a4f632f81eadfa2f69991e8 +size 1591454 diff --git a/hifi-content/howell/bots/AVATAR_TEST12.hfr b/hifi-content/howell/bots/AVATAR_TEST12.hfr new file mode 100644 index 000000000..62b8c6127 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST12.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa2b7bdf58b049e0e33f308d72a73a142c42a12faf49121beda3c6c49fbf44f4 +size 1686480 diff --git a/hifi-content/howell/bots/AVATAR_TEST13.hfr b/hifi-content/howell/bots/AVATAR_TEST13.hfr new file mode 100644 index 000000000..c51393d15 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST13.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54cefee9dc45885ac676525e175ea723e1a838abb80c9fc32f828c59e1acf65d +size 2204124 diff --git a/hifi-content/howell/bots/AVATAR_TEST14.hfr b/hifi-content/howell/bots/AVATAR_TEST14.hfr new file mode 100644 index 000000000..6a91c1bd2 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST14.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7faa106a9808d87784860dc7461c1d9c2fc27f612ef9cc57bdfc2b5c702c008 +size 1185194 diff --git a/hifi-content/howell/bots/AVATAR_TEST15.hfr b/hifi-content/howell/bots/AVATAR_TEST15.hfr new file mode 100644 index 000000000..5b52952e3 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST15.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e450bd4b3ef294984738a769da71b694bfc55940e1071a33efc8fbf9d8a58d51 +size 2887841 diff --git a/hifi-content/howell/bots/AVATAR_TEST16.hfr b/hifi-content/howell/bots/AVATAR_TEST16.hfr new file mode 100644 index 000000000..eb17e0191 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST16.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f242f9423b60c5f347fa2fb6b89c125ee921fc8fc7be6254d371ef756da02ea +size 1666494 diff --git a/hifi-content/howell/bots/AVATAR_TEST17.hfr b/hifi-content/howell/bots/AVATAR_TEST17.hfr new file mode 100644 index 000000000..4fcdb31aa --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST17.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08259f6135f2bac23632d50befd5a924c23b2791123ed23e051a7a9edc60ee58 +size 1426485 diff --git a/hifi-content/howell/bots/AVATAR_TEST18.hfr b/hifi-content/howell/bots/AVATAR_TEST18.hfr new file mode 100644 index 000000000..658395473 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST18.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98f3ff1147262a21ab6cd1a91e137ac75aef2f7ea84df1933fd6629a9558c8c1 +size 1363808 diff --git a/hifi-content/howell/bots/AVATAR_TEST19.hfr b/hifi-content/howell/bots/AVATAR_TEST19.hfr new file mode 100644 index 000000000..7cc8ef467 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST19.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bf086e1b8c0ab37cde6351a9fb7e0ca363e8d8a7a49ba6f0b45d20eb3b22e8a +size 985808 diff --git a/hifi-content/howell/bots/AVATAR_TEST2.hfr b/hifi-content/howell/bots/AVATAR_TEST2.hfr new file mode 100644 index 000000000..375651531 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST2.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e3038a4e34576fe52aa9ceda70cb066fe93ddd46782d3db44827e3ecffe34d9 +size 2178570 diff --git a/hifi-content/howell/bots/AVATAR_TEST20.hfr b/hifi-content/howell/bots/AVATAR_TEST20.hfr new file mode 100644 index 000000000..8611625cd --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST20.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49675f51a8981e99aa5bc079819568a96bba348519f44cd22cc4d55b5bf55932 +size 1739628 diff --git a/hifi-content/howell/bots/AVATAR_TEST3.hfr b/hifi-content/howell/bots/AVATAR_TEST3.hfr new file mode 100644 index 000000000..c405e31e4 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST3.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee10abed9d2152c503739887a5af8b9a1bb827a6f2a931db839113072f1cce0f +size 1667470 diff --git a/hifi-content/howell/bots/AVATAR_TEST4.hfr b/hifi-content/howell/bots/AVATAR_TEST4.hfr new file mode 100644 index 000000000..5cd58f9c4 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST4.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d2e20acb44e860edf402b2c8be36e3d510847b88276c9999a749ac6581f6e9a +size 3584851 diff --git a/hifi-content/howell/bots/AVATAR_TEST5.hfr b/hifi-content/howell/bots/AVATAR_TEST5.hfr new file mode 100644 index 000000000..d2902d69c --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST5.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d88321eb90c0b276cd98a12b8e7b9f69ed4581588389ad2541cebd63ff4773a +size 5587202 diff --git a/hifi-content/howell/bots/AVATAR_TEST6.hfr b/hifi-content/howell/bots/AVATAR_TEST6.hfr new file mode 100644 index 000000000..138ea7ec9 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST6.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0783ee0db7bac33092c443fdcdd3702db8e36fc9a8a62836371534c11a8c79cb +size 5949659 diff --git a/hifi-content/howell/bots/AVATAR_TEST7.hfr b/hifi-content/howell/bots/AVATAR_TEST7.hfr new file mode 100644 index 000000000..2bceec911 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST7.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce31d7e20ecba3ea824b7d0ca61e34a8e66e6b4cd415bfb76a658cf067f8984b +size 2389461 diff --git a/hifi-content/howell/bots/AVATAR_TEST8.hfr b/hifi-content/howell/bots/AVATAR_TEST8.hfr new file mode 100644 index 000000000..45f026812 --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST8.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:46c2efb60681234de3eb8b50dddc2a3fb8b800bdf1e7902e5e1daae7e332f25c +size 1879422 diff --git a/hifi-content/howell/bots/AVATAR_TEST9.hfr b/hifi-content/howell/bots/AVATAR_TEST9.hfr new file mode 100644 index 000000000..3496db33f --- /dev/null +++ b/hifi-content/howell/bots/AVATAR_TEST9.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab03e5e3ef6660decc90396b77b5ef337ec18ca44a4e73a448cbb107bfd03cee +size 2547568 diff --git a/hifi-content/howell/bots/_AVATAR_TEST5.hfr b/hifi-content/howell/bots/_AVATAR_TEST5.hfr new file mode 120000 index 000000000..3879f6d5f --- /dev/null +++ b/hifi-content/howell/bots/_AVATAR_TEST5.hfr @@ -0,0 +1 @@ +AVATAR_TEST15.hfr \ No newline at end of file diff --git a/hifi-content/howell/bots_new/AVATAR_TEST1.hfr b/hifi-content/howell/bots_new/AVATAR_TEST1.hfr new file mode 100644 index 000000000..6d13dd4f4 --- /dev/null +++ b/hifi-content/howell/bots_new/AVATAR_TEST1.hfr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8144f99773cda75e348020f2acc1bef6180a7577f5e48649316e26b7b177a2e6 +size 2232992 diff --git a/hifi-content/howell/usertesting/can_you_see_me.txt b/hifi-content/howell/usertesting/can_you_see_me.txt new file mode 100644 index 000000000..51ce371a0 --- /dev/null +++ b/hifi-content/howell/usertesting/can_you_see_me.txt @@ -0,0 +1 @@ +Shannon can you see this? \ No newline at end of file diff --git a/hifi-content/huffman/avatars/tubeboy/tubeboy.fst b/hifi-content/huffman/avatars/tubeboy/tubeboy.fst new file mode 100644 index 000000000..78d2321e0 --- /dev/null +++ b/hifi-content/huffman/avatars/tubeboy/tubeboy.fst @@ -0,0 +1,131 @@ +name = tubeboy +type = body+head +scale = 1 +filename = tubeboy/tubeboy.fbx +texdir = tubeboy/textures +joint = jointNeck = Neck +joint = jointRoot = Hips +joint = jointRightHand = RightHand +joint = jointLeftHand = LeftHand +joint = jointHead = HeadTop_End +joint = jointLean = Spine +freeJoint = LeftArm +freeJoint = LeftForeArm +freeJoint = RightArm +freeJoint = RightForeArm +bs = LipsLowerDown = LowerLipDown_Right = 0.69999999999999996 +bs = LipsLowerDown = LowerLipDown_Left = 0.69999999999999996 +bs = EyeOpen_L = EyesWide_Left = 1 +bs = LipsLowerOpen = LowerLipOut = 1 +bs = MouthDimple_L = Smile_Left = 0.25 +bs = BrowsU_L = BrowsUp_Left = 1 +bs = ChinLowerRaise = Jaw_Up = 1 +bs = MouthRight = Midmouth_Right = 1 +bs = JawLeft = JawRotateY_Left = 0.5 +bs = EyeOpen_R = EyesWide_Right = 1 +bs = LipsPucker = MouthNarrow_Right = 1 +bs = LipsPucker = MouthNarrow_Left = 1 +bs = EyeBlink_L = Blink_Left = 1 +bs = EyeBlink_R = Blink_Right = 1 +bs = JawOpen = MouthOpen = 0.69999999999999996 +bs = EyeSquint_L = Squint_Left = 1 +bs = BrowsU_C = BrowsUp_Right = 1 +bs = BrowsU_C = BrowsUp_Left = 1 +bs = MouthSmile_L = Smile_Left = 1 +bs = JawRight = Jaw_Right = 1 +bs = MouthFrown_R = Frown_Right = 1 +bs = Puff = CheekPuff_Right = 1 +bs = Puff = CheekPuff_Left = 1 +bs = BrowsD_R = BrowsDown_Right = 1 +bs = EyeSquint_R = Squint_Right = 1 +bs = MouthFrown_L = Frown_Left = 1 +bs = Sneer = Squint_Right = 0.5 +bs = Sneer = Squint_Left = 0.5 +bs = Sneer = NoseScrunch_Right = 0.75 +bs = Sneer = NoseScrunch_Left = 0.75 +bs = LipsUpperOpen = UpperLipOut = 1 +bs = JawFwd = JawForeward = 1 +bs = MouthLeft = Midmouth_Left = 1 +bs = MouthSmile_R = Smile_Right = 1 +bs = LipsUpperUp = UpperLipUp_Right = 0.69999999999999996 +bs = LipsUpperUp = UpperLipUp_Left = 0.69999999999999996 +bs = LipsUpperClose = UpperLipIn = 1 +bs = MouthDimple_R = Smile_Right = 0.25 +bs = LipsLowerClose = LowerLipIn = 1 +bs = LipsFunnel = TongueUp = 1 +bs = LipsFunnel = MouthWhistle_NarrowAdjust_Right = 0.5 +bs = LipsFunnel = MouthWhistle_NarrowAdjust_Left = 0.5 +bs = LipsFunnel = MouthNarrow_Right = 1 +bs = LipsFunnel = MouthNarrow_Left = 1 +bs = LipsFunnel = Jaw_Down = 0.35999999999999999 +bs = LipsFunnel = JawForeward = 0.39000000000000001 +bs = BrowsU_R = BrowsUp_Right = 1 +bs = ChinUpperRaise = UpperLipUp_Right = 0.5 +bs = ChinUpperRaise = UpperLipUp_Left = 0.5 +bs = BrowsD_L = BrowsDown_Left = 1 +jointIndex = RightArm = 16 +jointIndex = RightHandThumb1 = 35 +jointIndex = LeftUpLeg = 7 +jointIndex = Spine1 = 13 +jointIndex = LeftHandThumb2 = 60 +jointIndex = LeftToe_End = 11 +jointIndex = LeftHandPinky1 = 43 +jointIndex = LeftHandThumb4 = 62 +jointIndex = RightHandPinky1 = 19 +jointIndex = LeftLeg = 8 +jointIndex = RightHandThumb3 = 37 +jointIndex = RightHandMiddle4 = 30 +jointIndex = LeftHandPinky3 = 45 +jointIndex = RightHandMiddle1 = 27 +jointIndex = RightHandIndex3 = 33 +jointIndex = LeftHandIndex1 = 55 +jointIndex = LeftToeBase = 10 +jointIndex = LeftHandPinky4 = 46 +jointIndex = LeftHandRing4 = 50 +jointIndex = Head = 64 +jointIndex = LeftShoulder = 39 +jointIndex = RightHandRing3 = 25 +jointIndex = RightFoot = 4 +jointIndex = RightHandRing1 = 23 +jointIndex = RightHandThumb4 = 38 +jointIndex = RightHandRing4 = 26 +jointIndex = RightHandThumb2 = 36 +jointIndex = LeftHandPinky2 = 44 +jointIndex = Hips = 0 +jointIndex = RightHand = 18 +jointIndex = RightHandMiddle2 = 28 +jointIndex = LeftHandRing1 = 47 +jointIndex = RightToeBase = 5 +jointIndex = LeftHandMiddle4 = 54 +jointIndex = RightHandRing2 = 24 +jointIndex = Spine = 12 +jointIndex = HeadTop_End = 65 +jointIndex = LeftHandRing3 = 49 +jointIndex = Spine2 = 14 +jointIndex = LeftHandMiddle2 = 52 +jointIndex = LeftHandIndex3 = 57 +jointIndex = RightHandPinky4 = 22 +jointIndex = RightLeg = 3 +jointIndex = RightToe_End = 6 +jointIndex = LeftHandRing2 = 48 +jointIndex = LeftHandIndex2 = 56 +jointIndex = LeftHandThumb3 = 61 +jointIndex = RightHandIndex4 = 34 +jointIndex = LeftFoot = 9 +jointIndex = LeftForeArm = 41 +jointIndex = LeftHandMiddle3 = 53 +jointIndex = RightHandMiddle3 = 29 +jointIndex = Neck = 63 +jointIndex = RightForeArm = 17 +jointIndex = Layer_7 = 1 +jointIndex = LeftHandMiddle1 = 51 +jointIndex = RightUpLeg = 2 +jointIndex = RightHandPinky2 = 20 +jointIndex = LeftHand = 42 +jointIndex = RightHandIndex2 = 32 +jointIndex = LeftHandIndex4 = 58 +jointIndex = LeftArm = 40 +jointIndex = RightHandIndex1 = 31 +jointIndex = LeftHandThumb1 = 59 +jointIndex = RightHandPinky3 = 21 +jointIndex = RightShoulder = 15 diff --git a/hifi-content/huffman/avatars/tubeboy/tubeboy/tubeboy.fbx b/hifi-content/huffman/avatars/tubeboy/tubeboy/tubeboy.fbx new file mode 100644 index 000000000..c2bb6a750 --- /dev/null +++ b/hifi-content/huffman/avatars/tubeboy/tubeboy/tubeboy.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0fcf3223cc5affce57dfe1235611659812fa6a85b8d84449c1630cf8546a9b5 +size 4457056 diff --git a/hifi-content/huffman/ctf/Portal-Red-Blue.svo.json b/hifi-content/huffman/ctf/Portal-Red-Blue.svo.json new file mode 100644 index 000000000..50f0d3fed --- /dev/null +++ b/hifi-content/huffman/ctf/Portal-Red-Blue.svo.json @@ -0,0 +1,175 @@ +{ + "Entities": [ + { + "clientOnly": 0, + "collisionsWillMove": 1, + "compoundShapeURL": "http://hifi-production.s3.amazonaws.com/tutorials/pingPongGun/Pingpong-Gun-New.obj", + "created": "2017-02-27T19:00:27Z", + "dimensions": { + "x": 0.17742760479450226, + "y": 0.38749998807907104, + "z": 0.99309998750686646 + }, + "dynamic": 1, + "gravity": { + "x": 0, + "y": -5, + "z": 0 + }, + "id": "{891a0f4b-b8b2-4825-ace1-f566e8718782}", + "lastEdited": 1488229103067753, + "lastEditedBy": "{0f6b0911-7faf-45af-bfd0-9726a9ef0a2e}", + "modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/Pingportal-Gun-New.fbx?1", + "name": "Tutorial Ping Pong Gun", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "position": { + "x": 1.4289360046386719, + "y": 0, + "z": 1.4532890319824219 + }, + "queryAACube": { + "scale": 1.0806869268417358, + "x": 0.88859254121780396, + "y": -0.54034346342086792, + "z": 0.91294556856155396 + }, + "rotation": { + "w": 0.51259636878967285, + "x": -0.5248645544052124, + "y": 0.5236133337020874, + "z": -0.43306630849838257 + }, + "script": "http://hifi-content.s3.amazonaws.com/alan/dev/Scripts/ping-portal-lionsgate-blue.js?4", + "shapeType": "compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.1177130937576294,\"y\":0.12922893464565277,\"z\":0.08307232707738876},{\"x\":0.4934672713279724,\"y\":0.3605862259864807,\"z\":0.6394805908203125,\"w\":-0.4664038419723511}],\"LeftHand\":[{\"x\":0.09151676297187805,\"y\":0.13639454543590546,\"z\":0.09354984760284424},{\"x\":-0.19628101587295532,\"y\":0.6418180465698242,\"z\":0.2830369472503662,\"w\":0.6851521730422974}]}}}" + }, + { + "clientOnly": 0, + "color": { + "blue": 255, + "green": 166, + "red": 41 + }, + "created": "2017-02-27T19:00:27Z", + "cutoff": 90, + "dimensions": { + "x": 5.0777130126953125, + "y": 5.0777130126953125, + "z": 5.0777130126953125 + }, + "falloffRadius": 2.2000000476837158, + "id": "{51782e1b-983b-477d-9a6d-5ab550c198df}", + "intensity": 5, + "lastEdited": 1488229094210296, + "lastEditedBy": "{0f6b0911-7faf-45af-bfd0-9726a9ef0a2e}", + "name": "PingPortal-Light", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "parentID": "{891a0f4b-b8b2-4825-ace1-f566e8718782}", + "position": { + "x": -0.071898072957992554, + "y": 0.1922331303358078, + "z": 0.59060537815093994 + }, + "queryAACube": { + "scale": 26.384571075439453, + "x": -21.061281204223633, + "y": -13.358207702636719, + "z": -58.344821929931641 + }, + "rotation": { + "w": -0.14616614580154419, + "x": 0.68834972381591797, + "y": -0.69469749927520752, + "z": -0.14915692806243896 + }, + "type": "Light" + }, + { + "clientOnly": 0, + "collisionsWillMove": 1, + "compoundShapeURL": "http://hifi-production.s3.amazonaws.com/tutorials/pingPongGun/Pingpong-Gun-New.obj", + "created": "2017-02-27T20:45:19Z", + "dimensions": { + "x": 0.17742760479450226, + "y": 0.38749998807907104, + "z": 0.99309998750686646 + }, + "dynamic": 1, + "gravity": { + "x": 0, + "y": -5, + "z": 0 + }, + "id": "{25c38044-7ede-485c-815b-dddbf6496bcb}", + "lastEdited": 1488229023393654, + "lastEditedBy": "{0f6b0911-7faf-45af-bfd0-9726a9ef0a2e}", + "modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/PingPortal-Gun-red.fbx", + "name": "Portal-Gun", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "position": { + "x": 0, + "y": 0.0038486719131469727, + "z": 0 + }, + "queryAACube": { + "scale": 92.106178283691406, + "x": -54.764865875244141, + "y": -2.7994985580444336, + "z": -53.593635559082031 + }, + "rotation": { + "w": 0.64834010601043701, + "x": -0.34717363119125366, + "y": 0.36466187238693237, + "z": -0.57109308242797852 + }, + "script": "http://hifi-content.s3.amazonaws.com/alan/dev/Scripts/ping-portal-lionsgate-red.js", + "shapeType": "compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.1177130937576294,\"y\":0.12922893464565277,\"z\":0.08307232707738876},{\"x\":0.4934672713279724,\"y\":0.3605862259864807,\"z\":0.6394805908203125,\"w\":-0.4664038419723511}],\"LeftHand\":[{\"x\":0.09151676297187805,\"y\":0.13639454543590546,\"z\":0.09354984760284424},{\"x\":-0.19628101587295532,\"y\":0.6418180465698242,\"z\":0.2830369472503662,\"w\":0.6851521730422974}]}}}" + }, + { + "clientOnly": 0, + "color": { + "blue": 96, + "green": 23, + "red": 255 + }, + "created": "2017-02-27T20:45:19Z", + "cutoff": 90, + "dimensions": { + "x": 5.0777130126953125, + "y": 5.0777130126953125, + "z": 5.0777130126953125 + }, + "falloffRadius": 3.2000000476837158, + "id": "{e33b0529-361c-4515-b17c-534e4d1af5aa}", + "intensity": 5.4000000953674316, + "lastEdited": 1488229000832557, + "lastEditedBy": "{0f6b0911-7faf-45af-bfd0-9726a9ef0a2e}", + "name": "PingPortal-Light", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "parentID": "{25c38044-7ede-485c-815b-dddbf6496bcb}", + "position": { + "x": -0.071893095970153809, + "y": 0.1922280490398407, + "z": 0.5906517505645752 + }, + "queryAACube": { + "scale": 26.384571075439453, + "x": -18.223112106323242, + "y": -13.085569381713867, + "z": -64.876693725585938 + }, + "rotation": { + "w": -0.14616614580154419, + "x": 0.68831920623779297, + "y": -0.69469749927520752, + "z": -0.14915692806243896 + }, + "type": "Light" + } + ], + "Version": 66 +} diff --git a/hifi-content/huffman/ctf/README.md b/hifi-content/huffman/ctf/README.md new file mode 100644 index 000000000..78fd985d4 --- /dev/null +++ b/hifi-content/huffman/ctf/README.md @@ -0,0 +1,24 @@ +### ballClientEntity.js + + * Keeps track of whether it is being held locally. + * Has a message interface to release the ball. This message is sent when the + portal gun bullet/orb hits the user. + * Releases the ball when the goal is touched, and sends a message to the goal + +### goalClientEntity.js + + * Shoots fireworks when the ball is scored + * Manages a cooldown so the goal can only be triggered every 2 seconds (on the client, so technically if 2 clients + scored in a shorted period of time it would still trigger twice). + +### portalGunClientEntity.js + +Portal gun client entity script + +### portalBulletClientEntity.js + +Portal bullet client entity script. Teleports a user to the starting area when it hits a user + +### gunSpawnerClientEntity.js + +Spawns guns when it is clicked/grabbed/fargrabbed diff --git a/hifi-content/huffman/ctf/ballClientEntity.js b/hifi-content/huffman/ctf/ballClientEntity.js new file mode 100644 index 000000000..4a618ca2d --- /dev/null +++ b/hifi-content/huffman/ctf/ballClientEntity.js @@ -0,0 +1,67 @@ +(function() { + var self = this; + + var leftHeld = false; + var rightHeld = false; + + self.preload = function(entityID) { + self.entityID = entityID; + Script.addEventHandler(entityID, "collisionWithEntity", self.onCollide); + print('preload'); + }; + + self.startDistanceGrab = function(entityID, args) { + if (args[0] === 'left') { + leftHeld = true; + } else { + rightHeld = true; + } + print("startDistance", leftHeld, rightHeld); + }; + self.startNearGrab = function(entityID, args) { + if (args[0] === 'left') { + leftHeld = true; + } else { + rightHeld = true; + } + print("startNear", leftHeld, rightHeld); + }; + self.releaseGrab = function(entityID, args) { + if (args[0] === 'left') { + leftHeld = false; + } else { + rightHeld = false; + } + print("release", leftHeld, rightHeld); + }; + + self.onCollide = function(entityA, entityB, collision) { + var colliderName = Entities.getEntityProperties(entityB, 'name').name; + print("Collide", colliderName); + if (colliderName === "Portal/Goal") { + self.releaseBall(); + Entities.callEntityMethod(entityB, 'onScored'); + } + }; + + self.releaseBall = function() { + if (leftHeld || rightHeld) { + var hand; + if (leftHeld && rightHeld) { + hand = 'both'; + } else if (!leftHeld && rightHeld) { + hand = 'right'; + } else if (leftHeld && !rightHeld) { + hand = 'left'; + } + Messages.sendMessage("Hifi-Hand-Drop", hand); + } + }; + + Messages.subscribe("Portal-Game"); + Messages.messageReceived.connect(function(channel, message, sender) { + if (channel === "Portal-Game") { + self.releaseBall(); + } + }); +}); diff --git a/hifi-content/huffman/ctf/firework.js b/hifi-content/huffman/ctf/firework.js new file mode 100644 index 000000000..c723b34ed --- /dev/null +++ b/hifi-content/huffman/ctf/firework.js @@ -0,0 +1,147 @@ +// +// firework.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// Copyright 2015 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 +// + +/* globals randomVec3, randomInt, randomColor, getSounds, playFireworkShow:true */ + +Script.include("utils.js"); + +var emitters = []; + +var smokeTrailSettings = { + "name":"ParticlesTest Emitter", + "type": "ParticleEffect", + "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, + "maxParticles":1000, + "velocity": { x: 0, y: 18.0, z: 0 }, + "lifetime": 20, + "lifespan":3, + "emitRate":100, + "emitSpeed":0.5, + "speedSpread":0, + "emitOrientation":{"x":0,"y":0,"z":0,"w":1}, + "emitDimensions":{"x":0,"y":0,"z":0}, + "emitRadiusStart":0.5, + "polarStart":1, + "polarFinish":1, + "azimuthStart":0, + "azimuthFinish":0, + "emitterShouldTrail": true, + "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, + "accelerationSpread":{"x":0,"y":0,"z":0}, + "particleRadius":0.03999999910593033, + "radiusSpread":0, + "radiusStart":0.13999999910593033, + "radiusFinish":0.14, + "colorSpread":{"red":0,"green":0,"blue":0}, + "colorStart":{"red":255,"green":255,"blue":255}, + "colorFinish":{"red":255,"green":255,"blue":255}, + "alpha":1, + "alphaSpread":0, + "alphaStart":1, + "alphaFinish":0, + "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}; + +var fireworkSettings = { + "name":"ParticlesTest Emitter", + "type": "ParticleEffect", + "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, + "maxParticles":1000, + "lifetime": 20, + "lifespan":15, + "emitRate":2000, + "emitSpeed":2.5, + "speedSpread":1.0, + "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "emitDimensions":{"x":0,"y":0,"z":0}, + "emitRadiusStart":0.5, + "polarStart":0, + "polarFinish":Math.PI, + "azimuthStart":-Math.PI, + "azimuthFinish":Math.PI, + "emitAcceleration":{"x":0,"y":-1.70000001192092896,"z":0}, + "accelerationSpread":{"x":0,"y":0,"z":0}, + "particleRadius":0.02999999910593033, + "radiusSpread":0, + "radiusStart":0.13999999910593033, + "radiusFinish":0.14, + "colorSpread":{"red":0,"green":0,"blue":0}, + "colorStart":{"red":255,"green":255,"blue":255}, + "colorFinish":{"red":255,"green":255,"blue":255}, + "alpha":1, + "alphaSpread":0, + "alphaStart":1, + "alphaFinish":0, + "textures":"http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Particle-Spark.png" +}; + +var popSounds = getSounds([ + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav", + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav", + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav", + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav" +]); + +var launchSounds = getSounds([ + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire1.wav", + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire2.wav", + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire3.wav", + "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire4.wav" +]); + +function playRandomSound(sounds, options) { + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +function shootFirework(position, color, options) { + smokeTrailSettings.position = position; + smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, -5, 5); + smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, -5, 5); + + playRandomSound(launchSounds, { position: position, volume: 3.0 }); + var smokeID = Entities.addEntity(smokeTrailSettings); + + Script.setTimeout(function() { + Entities.editEntity(smokeID, { emitRate: 0 }); + var position = Entities.getEntityProperties(smokeID, ['position']).position; + fireworkSettings.position = position; + fireworkSettings.colorStart = color; + fireworkSettings.colorFinish = color; + var burstID = Entities.addEntity(fireworkSettings); + playRandomSound(popSounds, { position: position, volume: 3.0 }); + Script.setTimeout(function() { + Entities.editEntity(burstID, { emitRate: 0 }); + }, 250); + Script.setTimeout(function() { + Entities.deleteEntity(smokeID); + Entities.deleteEntity(burstID); + }, 10000); + }, 2000); +} + +playFireworkShow = function(position, numberOfFireworks, duration, offsetRange, colorBegin, colorEnd) { + for (var i = 0; i < numberOfFireworks; i++) { + var randomOffset = randomVec3(-offsetRange.x/2, offsetRange.x/2, + -offsetRange.y/2, offsetRange.y/2, + -offsetRange.z/2, offsetRange.z/2); + var randomPosition = Vec3.sum(position, randomOffset); + Script.setTimeout(function(position) { + return function() { + var color = randomColor(colorBegin.red, colorEnd.red, + colorBegin.green, colorEnd.green, + colorBegin.blue, colorEnd.blue); + shootFirework(position, color, fireworkSettings); + }; + }(randomPosition), Math.random() * duration); + } +}; +//var position = Vec3.sum(MyAvatar.position, { x: 30, y: 0, z: 0 }); +//playFireworkShow(position, 10, 2000, { x: 0, y: 0, z: 0 }, { red: 0, green: 0, blue: 200 }, { red: 0, green: 0, blue: 200 }); diff --git a/hifi-content/huffman/ctf/goalClientEntity.js b/hifi-content/huffman/ctf/goalClientEntity.js new file mode 100644 index 000000000..b16e63594 --- /dev/null +++ b/hifi-content/huffman/ctf/goalClientEntity.js @@ -0,0 +1,50 @@ +/* globals playFireworkShow */ + +(function() { + Script.include("firework.js?" + Date.now()); + + var self = this; + var teleportSound = SoundCache.getSound(Script.resolvePath("sounds/teleport.raw")); + var inCooldown = false; + + self.preload = function(entityID) { + self.entityID = entityID; + + var userData = Entities.getEntityProperties(entityID, 'userData').userData; + try { + userData = JSON.parse(userData); + if (userData.beginColor !== undefined && userData.endColor !== undefined) { + self.beginColor = userData.beginColor; + self.endColor = userData.endColor; + print("bgin:", self.beginColor.red, self.beginColor.green, self.beginColor.blue); + } else { + print("ERROR, colors not found"); + } + } catch (e) { + print("ERROR, could not find gun color"); + } + }; + + self.onScored = function() { + if (inCooldown) { + return; + } + + var position = Entities.getEntityProperties(self.entityID, 'position').position; + playFireworkShow(position, 20, 3000, + { x: 5, y: 2, z: 5 }, + self.beginColor, + self.endColor); + Audio.playSound(teleportSound, { + position: position, + volume: 0.40 + }); + inCooldown = true; + Script.setTimeout(function() { + inCooldown = false; + }, 2000); + }; +}); + + +// http://hifi-content.s3.amazonaws.com/caitlyn/production/soundEmitter/soundLoopEmitter.js diff --git a/hifi-content/huffman/ctf/gunSpawnerClientEntity.js b/hifi-content/huffman/ctf/gunSpawnerClientEntity.js new file mode 100644 index 000000000..8121cfc7a --- /dev/null +++ b/hifi-content/huffman/ctf/gunSpawnerClientEntity.js @@ -0,0 +1,124 @@ +(function() { + var GUN_RED_MODEL_URL = Script.resolvePath("models/portalgun_red.fbx"); + var GUN_BLUE_MODEL_URL = Script.resolvePath("models/portalgun_blue.fbx"); + + var gunProps = { + "collisionsWillMove": 1, + "compoundShapeURL": Script.resolvePath("models/portalgun_collider.obj"), + "dimensions": { + "x": 0.17742760479450226, + "y": 0.38749998807907104, + "z": 0.99309998750686646 + }, + "dynamic": 1, + "gravity": { + "x": 0, + "y": -5, + "z": 0 + }, + "modelURL": Script.resolvePath("models/portalgun_red.fbx"), + "name": "Portal/Gun", + "position": { + "x": 1.4289360046386719, + "y": 0, + "z": 1.4532890319824219 + }, + "rotation": { + "w": 0.51259636878967285, + "x": -0.5248645544052124, + "y": 0.5236133337020874, + "z": -0.43306630849838257 + }, + //lifetime: 100, + velocity: { + x: 0, + y: 0.1, + z: 0 + }, + "script": Script.resolvePath("portalGunClientEntity.js?" + Date.now()), + "shapeType": "compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.1177130937576294,\"y\":0.12922893464565277,\"z\":0.08307232707738876},{\"x\":0.4934672713279724,\"y\":0.3605862259864807,\"z\":0.6394805908203125,\"w\":-0.4664038419723511}],\"LeftHand\":[{\"x\":0.09151676297187805,\"y\":0.13639454543590546,\"z\":0.09354984760284424},{\"x\":-0.19628101587295532,\"y\":0.6418180465698242,\"z\":0.2830369472503662,\"w\":0.6851521730422974}]}}}" + }; + + var lightProps = { + //lifetime: 100, + "color": { + "blue": 255, + "green": 166, + "red": 41 + }, + "cutoff": 90, + "dimensions": { + "x": 5.0777130126953125, + "y": 5.0777130126953125, + "z": 5.0777130126953125 + }, + "falloffRadius": 2.2000000476837158, + "intensity": 5, + "name": "Portal/GunLight", + "localPosition": { + x: 0, + y: 0.1, + z: 0.5 + }, + "type": "Light" + }; + + var gunData = { + red: { + modelURL: GUN_RED_MODEL_URL, + lightColor: { + red: 255, + green: 23, + blue: 96, + } + }, + blue: { + modelURL: GUN_BLUE_MODEL_URL, + lightColor: { + red: 41, + green: 166, + blue: 255, + } + } + }; + + var inCooldown = false; + + this.preload = function(entityID) { + this.entityID = entityID; + }; + + function spawnWeapons() { + if (inCooldown) { + return; + } + + var position = Entities.getEntityProperties(this.entityID, 'position').position; + + var userData = JSON.parse(gunProps.userData); + var colors = ['red', 'blue']; + for (var i = 0; i < colors.length; ++i) { + var color = colors[i]; + gunProps.modelURL = gunData[color].modelURL; + gunProps.position = position; + userData.color = color; + gunProps.userData = JSON.stringify(userData); + var gunID = Entities.addEntity(gunProps); + + lightProps.color = gunData[color].lightColor; + lightProps.parentID = gunID; + Entities.addEntity(lightProps); + } + + inCooldown = true; + Script.setTimeout(function() { + inCooldown = false; + }, 2000); + } + + this.startNearTrigger = spawnWeapons; + this.startFarTrigger = spawnWeapons; + this.clickDownOnEntity = spawnWeapons; +}); diff --git a/hifi-content/huffman/ctf/models/portalgun.fbx b/hifi-content/huffman/ctf/models/portalgun.fbx new file mode 120000 index 000000000..073c1557b --- /dev/null +++ b/hifi-content/huffman/ctf/models/portalgun.fbx @@ -0,0 +1 @@ +../../../alan/dev/Pingportal-Gun-New.fbx \ No newline at end of file diff --git a/hifi-content/huffman/ctf/models/portalgun_blue.fbx b/hifi-content/huffman/ctf/models/portalgun_blue.fbx new file mode 120000 index 000000000..073c1557b --- /dev/null +++ b/hifi-content/huffman/ctf/models/portalgun_blue.fbx @@ -0,0 +1 @@ +../../../alan/dev/Pingportal-Gun-New.fbx \ No newline at end of file diff --git a/hifi-content/huffman/ctf/models/portalgun_collider.obj b/hifi-content/huffman/ctf/models/portalgun_collider.obj new file mode 120000 index 000000000..8557ff2a3 --- /dev/null +++ b/hifi-content/huffman/ctf/models/portalgun_collider.obj @@ -0,0 +1 @@ +../../../alan/dev/Pingpong-Gun-New.obj \ No newline at end of file diff --git a/hifi-content/huffman/ctf/models/portalgun_red.fbx b/hifi-content/huffman/ctf/models/portalgun_red.fbx new file mode 120000 index 000000000..b02853b30 --- /dev/null +++ b/hifi-content/huffman/ctf/models/portalgun_red.fbx @@ -0,0 +1 @@ +../../../alan/dev/PingPortal-Gun-red.fbx \ No newline at end of file diff --git a/hifi-content/huffman/ctf/origina_portal_gun.js b/hifi-content/huffman/ctf/origina_portal_gun.js new file mode 100644 index 000000000..89bb5fa66 --- /dev/null +++ b/hifi-content/huffman/ctf/origina_portal_gun.js @@ -0,0 +1,210 @@ +// pingPongGun.js +// +// Script Type: Entity +// Created by James B. Pollack @imgntn on 9/21/2015 +// Copyright 2015 High Fidelity, Inc. +// +// This script shoots a ping pong ball. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + var _this = this; + + var SHOOTING_SOUND_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/Sounds/Gun/GunFire02.wav'; + + function PingPongGun() { + return; + } + + //if the trigger value goes below this value, reload the gun. + var RELOAD_THRESHOLD = 0.95; + var GUN_TIP_FWD_OFFSET = -1; + var GUN_TIP_UP_OFFSET = 0.12; + var GUN_FORCE = 20; + var BALL_RESTITUTION = 0.2; + var BALL_LINEAR_DAMPING = 0.1; + var BALL_DENSITY = 10000; + var BALL_GRAVITY = { + x: 0, + y: -4.8, + z: 0 + }; + + var PING_PONG_GUN_GRAVITY = { + x: 0, + y: -10, + z: 0 + }; + + var BALL_DIMENSIONS = { + x: 2.5, + y: 2.5, + z: 2.5 + }; + + var BALL_ANGULAR_VEL = { + x: 2, + y: 3, + z: 1 + }; + + + + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT, + ]; + + + PingPongGun.prototype = { + hand: null, + gunTipPosition: null, + canShoot: false, + canShootTimeout: null, + + startEquip: function(entityID, args) { + this.hand = args[0] == "left" ? 0 : 1; + }, + + continueEquip: function(entityID, args) { + if (this.canShootTimeout !== null) { + Script.clearTimeout(this.canShootTimeout); + } + this.checkTriggerPressure(this.hand); + }, + + releaseEquip: function(entityID, args) { + var _this = this; + this.canShootTimeout = Script.setTimeout(function() { + _this.canShoot = false; + }, 250); + }, + + checkTriggerPressure: function(gunHand) { + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[gunHand]); + if (this.triggerValue < RELOAD_THRESHOLD) { + this.canShoot = true; + } else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true) { + var gunProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + this.shootBall(gunProperties); + this.canShoot = false; + } + + return; + }, + + shootBall: function(gunProperties) { + var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, 180, 0))); + forwardVec = Vec3.normalize(forwardVec); + forwardVec = Vec3.multiply(forwardVec, GUN_FORCE); + var gunTipPosition = this.getGunTipPosition(gunProperties); + + var projectileProperties = { + name: 'Glow-Projectile', + type: 'Model', + modelURL: "http://hifi-content.s3.amazonaws.com/alan/dev/Glow-ball-blue.fbx", + dimensions: BALL_DIMENSIONS, + damping: BALL_LINEAR_DAMPING, + gravity: BALL_GRAVITY, + restitution: BALL_RESTITUTION, + density: BALL_DENSITY, + dynamic: true, + rotation: gunProperties.rotation, + position: gunTipPosition, + gravity: PING_PONG_GUN_GRAVITY, + angularDamping: 0, + angularVelocity: BALL_ANGULAR_VEL, + velocity: forwardVec, + lifetime: 10, + collisionless: true, + visible: true, + }; + + var projectileID = Entities.addEntity(projectileProperties); + + + var portalProperties = { + name: 'Portal-Projectile', + type: 'Sphere', + dimensions: BALL_DIMENSIONS, + parentID: projectileID, + damping: BALL_LINEAR_DAMPING, + gravity: BALL_GRAVITY, + restitution: BALL_RESTITUTION, + density: BALL_DENSITY, + dynamic: false, + rotation: gunProperties.rotation, + position: gunTipPosition, + gravity: PING_PONG_GUN_GRAVITY, + angularDamping: 0, + angularVelocity: BALL_ANGULAR_VEL, + velocity: forwardVec, + lifetime: 10, + visible: false, + script: 'http://hifi-content.s3.amazonaws.com/alan/dev/Scripts/portal-lionsgate.js', + collisionless: true, + }; + + Entities.addEntity(portalProperties); + + + this.playSoundAtCurrentPosition(gunProperties.position); + }, + + playSoundAtCurrentPosition: function(position) { + var audioProperties = { + volume: 0.9, + position: position + }; + + Audio.playSound(this.SHOOTING_SOUND, audioProperties); + }, + + getGunTipPosition: function(properties) { + //the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position + var frontVector = Quat.getFront(properties.rotation); + var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET); + var upVector = Quat.getUp(properties.rotation); + var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET); + + var gunTipPosition = Vec3.sum(properties.position, frontOffset); + gunTipPosition = Vec3.sum(gunTipPosition, upOffset); + + return gunTipPosition; + }, + + preload: function(entityID) { + this.entityID = entityID; + this.SHOOTING_SOUND = SoundCache.getSound(SHOOTING_SOUND_URL); + // this.createTipEntity(entityID); + }, + createTipEntity: function(entityID) { + //for debugging where its going to shoot from + var gunProperties = Entities.getEntityProperties(entityID, ["position", "rotation"]); + + var tipProps = { + name: 'Ping pong tip test', + dimensions: { + x: 0.1, + y: 0.1, + z: 0.1 + }, + color: { + red: 0, + green: 255, + blue: 0 + }, + type: 'Box', + parentID: entityID, + position: this.getGunTipPosition(gunProperties) + }; + var tip = Entities.addEntity(tipProps); + } + + }; + + // entity scripts should return a newly constructed object of our type + return new PingPongGun(); +}); \ No newline at end of file diff --git a/hifi-content/huffman/ctf/portalBulletClientEntity.js b/hifi-content/huffman/ctf/portalBulletClientEntity.js new file mode 100644 index 000000000..0b5e7f860 --- /dev/null +++ b/hifi-content/huffman/ctf/portalBulletClientEntity.js @@ -0,0 +1,47 @@ +(function() { + this.preload = function(entityID) { + print("Loading portal bullet script"); + + this.teleportSound = SoundCache.getSound(Script.resolvePath("sounds/teleport.raw")); + this.portalTargetLocation = undefined; + + var userData = Entities.getEntityProperties(entityID, 'userData').userData; + try { + this.portalTargetLocation = JSON.parse(userData).portalTargetLocation; + } catch (e) { + this.portalTargetLocation = undefined; + } + + if (this.portalTargetLocation === undefined) { + print("ERROR, could not find portalTargetLocation in userData"); + } else { + print("Portal target location is: ", this.portalTargetLocation); + } + }; + + this.enterEntity = function(entityID) { + print("Entered bullet entity, the destination is " + this.portalTargetLocation); + + if (this.teleportSound.downloaded) { + var position = Entities.getEntityProperties(this.entityID, 'position').position; + Audio.playSound(this.teleportSound, { + position: position, + volume: 0.40, + localOnly: true + }); + } + + if (this.portalTargetLocation !== undefined) { + print("Teleporting to " + this.portalTargetLocation); + Window.location = this.portalTargetLocation; + } + + // Notify any instances of the ball that we have been hit ensuring that + // the ball will be dropped if we are holding it. + Messages.sendLocalMessage("Portal-Game", "hit"); + }; + + this.unload = function() { + print("unloading teleport script"); + }; +}); diff --git a/hifi-content/huffman/ctf/portalGunClientEntity.js b/hifi-content/huffman/ctf/portalGunClientEntity.js new file mode 100644 index 000000000..b7c43e3ff --- /dev/null +++ b/hifi-content/huffman/ctf/portalGunClientEntity.js @@ -0,0 +1,222 @@ +// pingPongGun.js +// +// Script Type: Entity +// Created by James B. Pollack @imgntn on 9/21/2015 +// Copyright 2015 High Fidelity, Inc. +// +// This script shoots a ping pong ball. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + var TRIGGER_THRESHOLD = 0.3; + + var BULLET_BLUE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Glow-ball-blue.fbx"; + var BULLET_RED_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Glow-ball-red.fbx"; + + var GUN_LOAD_SOUND_URL = "https://hifi-content.s3.amazonaws.com/DomainContent/Event%20/Sounds/Gun/GunLoad02.wav"; + var GUN_FIRE1_SOUND_URL = "https://hifi-content.s3.amazonaws.com/DomainContent/Event%20/Sounds/Gun/GunFire01.wav"; + var GUN_FIRE2_SOUND_URL = "https://hifi-content.s3.amazonaws.com/DomainContent/Event%20/Sounds/Gun/GunFire02.wav"; + var GUN_FIRE3_SOUND_URL = "https://hifi-content.s3.amazonaws.com/DomainContent/Event%20/Sounds/Gun/GunFire03.wav"; + + var GUN_TIP_FWD_OFFSET = -1; + var GUN_TIP_UP_OFFSET = 0.12; + var GUN_FORCE = 20; + var BALL_RESTITUTION = 0.2; + var BALL_LINEAR_DAMPING = 0.1; + var BALL_DENSITY = 10000; + + var BALL_GRAVITY = { + x: 0, + y: -10, + z: 0 + }; + + var BALL_DIMENSIONS = { + x: 2.5, + y: 2.5, + z: 2.5 + }; + + var BALL_COLLIDER_DIMENSIONS = { + x: 0.94, + y: 2.0, + z: 0.94 + }; + + var BALL_ANGULAR_VEL = { + x: 2, + y: 3, + z: 1 + }; + + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT + ]; + + function PortalGun() { + } + + PortalGun.prototype = { + hand: null, + gunTipPosition: null, + cooldownActive: false, + + preload: function(entityID) { + this.entityID = entityID; + this.gunFireSound = SoundCache.getSound(GUN_FIRE1_SOUND_URL); + this.gunLoadSound = SoundCache.getSound(GUN_LOAD_SOUND_URL); + + this.hasReleasedInitialTriggerPress = false; + + this.color = 'red'; + + var userData = Entities.getEntityProperties(entityID, 'userData').userData; + try { + userData = JSON.parse(userData); + if (userData.color === 'red' || userData.color === 'blue') { + this.color = userData.color; + } else { + print("ERROR, invalid color:", userData.color); + } + } catch (e) { + print("ERROR, could not find gun color"); + } + }, + startEquip: function(entityID, args) { + this.hand = args[0] === "left" ? 0 : 1; + }, + continueEquip: function(entityID, args) { + if (this.cooldownActive) { + return; + } + + var triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]); + if (triggerValue > TRIGGER_THRESHOLD) { + if (this.hasReleasedInitialTriggerPress) { + this.shootBall(); + } + } else { + this.hasReleasedInitialTriggerPress = true; + } + }, + releaseEquip: function(entityID, args) { + }, + shootBall: function() { + if (this.cooldownActive) { + print("Not allowing portal bullet to be shot while cooldown active"); + return; + } + Controller.triggerHapticPulse(10.0, 0.5, this.hand); + + var gunProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + + var gunTipPosition = this.getGunTipPosition(gunProperties); + + var audioProperties = { + volume: 0.9, + position: gunTipPosition, + localOnly: true + }; + + Audio.playSound(this.gunFireSound, audioProperties); + + var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, 180, 0))); + forwardVec = Vec3.normalize(forwardVec); + forwardVec = Vec3.multiply(forwardVec, GUN_FORCE); + + var projectileProperties = { + name: 'CTF/PortalBullet', + type: 'Model', + modelURL: this.color === 'blue' ? BULLET_BLUE_MODEL_URL : BULLET_RED_MODEL_URL, + dimensions: BALL_DIMENSIONS, + damping: BALL_LINEAR_DAMPING, + gravity: BALL_GRAVITY, + restitution: BALL_RESTITUTION, + density: BALL_DENSITY, + dynamic: true, + rotation: gunProperties.rotation, + position: gunTipPosition, + angularDamping: 0, + angularVelocity: BALL_ANGULAR_VEL, + velocity: forwardVec, + lifetime: 10, + collisionless: true, + visible: true + }; + var projectileID = Entities.addEntity(projectileProperties); + + var portalProperties = { + name: 'CTF/PortalCollider', + type: 'Sphere', + localPosition: { x: 0, y: 0, z: 0 }, + dimensions: BALL_DIMENSIONS, + parentID: projectileID, + dynamic: false, + lifetime: 10, + visible: false, + script: Script.resolvePath("portalBulletClientEntity.js"), + collisionless: true, + userData: JSON.stringify({ + //portalTargetLocation: "hifi://lionsgate.highfidelity.io/-104.376,-0.496867,-8.28224/0,0.721841,0,0.692059" + portalTargetLocation: "/16.0555,-0.372284,18.5259/0,0.631228,0,0.775597" + }) + }; + Entities.addEntity(portalProperties); + + var self = this; + this.cooldownActive = true; + Script.setTimeout(function() { + var gunProperties = Entities.getEntityProperties(self.entityID, ["position", "rotation"]); + var gunTipPosition = self.getGunTipPosition(gunProperties); + var audioProperties = { + volume: 0.9, + position: gunTipPosition, + localOnly: true + }; + Audio.playSound(self.gunLoadSound, audioProperties); + self.cooldownActive = false; + }, 1000); + }, + getGunTipPosition: function(properties) { + // the tip of the gun is going to be in a different place than the center, + // so we move in space relative to the model to find that position + var frontVector = Quat.getFront(properties.rotation); + var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET); + var upVector = Quat.getUp(properties.rotation); + var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET); + + var gunTipPosition = Vec3.sum(properties.position, frontOffset); + gunTipPosition = Vec3.sum(gunTipPosition, upOffset); + + return gunTipPosition; + }, + createTipEntity: function(entityID) { + // for debugging where its going to shoot from + var gunProperties = Entities.getEntityProperties(entityID, ["position", "rotation"]); + + var tipProps = { + name: 'Ping pong tip test', + dimensions: { + x: 0.1, + y: 0.1, + z: 0.1 + }, + color: { + red: 0, + green: 255, + blue: 0 + }, + type: 'Box', + parentID: entityID, + position: this.getGunTipPosition(gunProperties) + }; + Entities.addEntity(tipProps); + } + }; + + // entity scripts should return a newly varructed object of our type + return new PortalGun(); +}); diff --git a/hifi-content/huffman/ctf/portalgun.json b/hifi-content/huffman/ctf/portalgun.json new file mode 100644 index 000000000..cbd6402a4 --- /dev/null +++ b/hifi-content/huffman/ctf/portalgun.json @@ -0,0 +1,81 @@ +{ + "Entities": [ + { + "clientOnly": 0, + "collisionsWillMove": 1, + "compoundShapeURL": "http://hifi-production.s3.amazonaws.com/tutorials/pingPongGun/Pingpong-Gun-New.obj", + "created": "2016-11-04T22:25:04Z", + "dimensions": { + "x": 0.17742760479450226, + "y": 0.38749998807907104, + "z": 0.99309998750686646 + }, + "dynamic": 1, + "gravity": { + "x": 0, + "y": -5, + "z": 0 + }, + "id": "{a871719d-051d-4899-81f8-f624c04c3e3a}", + "modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/Pingportal-Gun-New.fbx?1", + "name": "Tutorial Ping Pong Gun", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "queryAACube": { + "scale": 1.0806869268417358, + "x": -0.54034346342086792, + "y": -0.54034346342086792, + "z": -0.54034346342086792 + }, + "rotation": { + "w": -0.14616614580154419, + "x": -0.68838024139404297, + "y": 0.69466698169708252, + "z": 0.14915692806243896 + }, + "script": "http://hifi-content.s3.amazonaws.com/alan/dev/Scripts/ping-portal-welcome.js?3", + "shapeType": "compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.1177130937576294,\"y\":0.12922893464565277,\"z\":0.08307232707738876},{\"x\":0.4934672713279724,\"y\":0.3605862259864807,\"z\":0.6394805908203125,\"w\":-0.4664038419723511}],\"LeftHand\":[{\"x\":0.09151676297187805,\"y\":0.13639454543590546,\"z\":0.09354984760284424},{\"x\":-0.19628101587295532,\"y\":0.6418180465698242,\"z\":0.2830369472503662,\"w\":0.6851521730422974}]}}}" + }, + { + "clientOnly": 0, + "color": { + "blue": 255, + "green": 166, + "red": 41 + }, + "created": "2016-11-04T22:55:39Z", + "cutoff": 90, + "dimensions": { + "x": 5.0777130126953125, + "y": 5.0777130126953125, + "z": 5.0777130126953125 + }, + "falloffRadius": 1.7000000476837158, + "id": "{a240a5b9-8ec5-46f7-a443-fd99ee08ba33}", + "intensity": 3.2999999523162842, + "name": "PingPortal-Light", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "parentID": "{a871719d-051d-4899-81f8-f624c04c3e3a}", + "position": { + "x": -0.071898072957992554, + "y": 0.1922331303358078, + "z": 0.59060537815093994 + }, + "queryAACube": { + "scale": 8.7948570251464844, + "x": 6.5513162612915039, + "y": -4.9521479606628418, + "z": -150.72532653808594 + }, + "rotation": { + "w": -0.14616614580154419, + "x": 0.68838024139404297, + "y": -0.69466698169708252, + "z": -0.14915692806243896 + }, + "type": "Light" + } + ], + "Version": 64 +} diff --git a/hifi-content/huffman/ctf/sounds/gunFire.wav b/hifi-content/huffman/ctf/sounds/gunFire.wav new file mode 100644 index 000000000..88b11e741 --- /dev/null +++ b/hifi-content/huffman/ctf/sounds/gunFire.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99e52a695d2477a48f71da9f15f40f02ec1073768eba8e26ed0cda07c34e93cb +size 145056 diff --git a/hifi-content/huffman/ctf/sounds/pong_sound.wav b/hifi-content/huffman/ctf/sounds/pong_sound.wav new file mode 100644 index 000000000..388d1bad1 --- /dev/null +++ b/hifi-content/huffman/ctf/sounds/pong_sound.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0bab5297e882dd92ca7fcb5f1e043386249d28cc5a013fc7a48c2660386c81aa +size 46926 diff --git a/hifi-content/huffman/ctf/sounds/teleport.raw b/hifi-content/huffman/ctf/sounds/teleport.raw new file mode 100644 index 0000000000000000000000000000000000000000..7ee3b4ce483261c37f95535d4f45583df911c396 GIT binary patch literal 106592 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�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 ZhYue<eE9I;!-o$aK79D_;loFA{4d%u-o^j` literal 0 HcmV?d00001 diff --git a/hifi-content/huffman/ctf/spawnPortalGun.js b/hifi-content/huffman/ctf/spawnPortalGun.js new file mode 100644 index 000000000..531216a36 --- /dev/null +++ b/hifi-content/huffman/ctf/spawnPortalGun.js @@ -0,0 +1,99 @@ +var GUN_RED_MODEL_URL = Script.resolvePath("models/portalgun_red.fbx"); +var GUN_BLUE_MODEL_URL = Script.resolvePath("models/portalgun_blue.fbx"); + +var gunProps = { + "collisionsWillMove": 1, + "compoundShapeURL": Script.resolvePath("models/portalgun_collider.obj"), + "dimensions": { + "x": 0.17742760479450226, + "y": 0.38749998807907104, + "z": 0.99309998750686646 + }, + "dynamic": 1, + "gravity": { + "x": 0, + "y": -5, + "z": 0 + }, + "modelURL": Script.resolvePath("models/portalgun_red.fbx"), + "name": "Portal/Gun", + "position": { + "x": 1.4289360046386719, + "y": 0, + "z": 1.4532890319824219 + }, + "rotation": { + "w": 0.51259636878967285, + "x": -0.5248645544052124, + "y": 0.5236133337020874, + "z": -0.43306630849838257 + }, + lifetime: 100, + velocity: { + x: 0, + y: 0.5, + z: 0 + }, + "script": Script.resolvePath("portalGunClientEntity.js?" + Date.now()), + "shapeType": "compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.1177130937576294,\"y\":0.12922893464565277,\"z\":0.08307232707738876},{\"x\":0.4934672713279724,\"y\":0.3605862259864807,\"z\":0.6394805908203125,\"w\":-0.4664038419723511}],\"LeftHand\":[{\"x\":0.09151676297187805,\"y\":0.13639454543590546,\"z\":0.09354984760284424},{\"x\":-0.19628101587295532,\"y\":0.6418180465698242,\"z\":0.2830369472503662,\"w\":0.6851521730422974}]}}}" +}; + +var lightProps = { + lifetime: 100, + "color": { + "blue": 255, + "green": 166, + "red": 41 + }, + "cutoff": 90, + "dimensions": { + "x": 5.0777130126953125, + "y": 5.0777130126953125, + "z": 5.0777130126953125 + }, + "falloffRadius": 2.2000000476837158, + "intensity": 5, + "name": "Portal/GunLight", + "localPosition": { + x: 0, + y: 0.1, + z: 0.5 + }, + "type": "Light" +}; + +var userData = JSON.parse(gunProps.userData); +var gunData = { + red: { + modelURL: GUN_RED_MODEL_URL, + lightColor: { + red: 255, + green: 23, + blue: 96, + } + }, + blue: { + modelURL: GUN_BLUE_MODEL_URL, + lightColor: { + red: 41, + green: 166, + blue: 255, + } + } +}; +var models = [GUN_RED_MODEL_URL, GUN_BLUE_MODEL_URL]; +var colors = ['red', 'blue']; +for (var i = 0; i < colors.length; ++i) { + var color = colors[i]; + gunProps.modelURL = gunData[color].modelURL; + gunProps.position = MyAvatar.position; + userData.color = color; + gunProps.userData = JSON.stringify(userData); + var gunID = Entities.addEntity(gunProps); + + lightProps.color = gunData[color].lightColor; + lightProps.parentID = gunID; + Entities.addEntity(lightProps); +} diff --git a/hifi-content/huffman/ctf/utils.js b/hifi-content/huffman/ctf/utils.js new file mode 100644 index 000000000..4cc179b81 --- /dev/null +++ b/hifi-content/huffman/ctf/utils.js @@ -0,0 +1,93 @@ +// +// utils.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// Copyright 2015 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 +// + +randomInt = function(low, high) { + print("low, high", low, high); + return Math.floor(randomFloat(low, high)); +}; + +randomFloat = function(low, high) { + if (high === undefined) { + high = low; + low = 0; + } + return low + Math.random() * (high - low); +}; + +randomColor = function(redMin, redMax, greenMin, greenMax, blueMin, blueMax) { + return { + red: Math.ceil(randomInt(redMin, redMax)), + green: Math.ceil(randomInt(greenMin, greenMax)), + blue: Math.ceil(randomInt(blueMin, blueMax)), + } +}; + +randomVec3 = function(xMin, xMax, yMin, yMax, zMin, zMax) { + return { + x: randomFloat(xMin, xMax), + y: randomFloat(yMin, yMax), + z: randomFloat(zMin, zMax), + } +}; + +getSounds = function(soundURLs) { + var sounds = []; + for (var i = 0; i < soundURLs.length; ++i) { + sounds.push(SoundCache.getSound(soundURLs[i], false)); + } + return sounds; +}; + +playRandomSound = function(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + return Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +shallowCopy = function(obj) { + var copy = {} + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +} + +findEntity = function(properties, searchRadius) { + var entities = findEntities(properties, searchRadius); + return entities.length > 0 ? entities[0] : null; +} + +// Return all entities with properties `properties` within radius `searchRadius` +findEntities = function(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} diff --git a/hifi-content/huffman/essTest.js b/hifi-content/huffman/essTest.js new file mode 100644 index 000000000..698873da6 --- /dev/null +++ b/hifi-content/huffman/essTest.js @@ -0,0 +1,9 @@ +(function() { + print("Inside ctor"); + this.preload = function() { + print("inside preload"); + } + this.unload = function() { + print("inside preload"); + } +});