content/hifi-content/clement/dev/asdf/crash.js
2022-02-13 22:19:19 +01:00

602 lines
22 KiB
JavaScript

// ACCleanupAndSpawnBot.js
//
// Created by Thijs Wenker on 9/26/2016
//
// This Assignment Client script cleans up a the defined
// 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
// Times when the cleanup script runs (on a daily basis 00:00 -> 23:59)
var RUN_WHEN = [
'1:00',
'3:00',
'5:00',
'7:00',
'9:00',
'11:00',
'13:00',
'15:00',
'17:00',
'19:00',
'21:00',
'23:00'
];
// Cleanup filters
//
// Allows the following entry-types:
// Name (string) eg: 'This is a cube'
// Name Regular Expression (RexExp) eg: /Cube[0-9]+/
// Filter Object (JS Object eg:
// {
// name: 'Cube',
// locked: false,
// visible: true
// }
var CLEANUP_FILTER = [
{
locked: 0,
clientOnly: 0
}
];
// The script will only run in the domain with the following placename:
// (The PLACENAME_LOCK is only effective when the script is ran in Interface, not for Assignment Client scripts)
var PLACENAME_LOCK = 'Pumpkin';
var DISPLAY_NAME = 'Mr. Resetti';
var DEFAULT_LIFETIME = 1800;
var JSON_PATH = 'https://hifi-content.s3.amazonaws.com/DomainContent/Welcome%20Area/Scripts/';
// IMPORT_ENTITIES supports JSON exported entities using importEntitiesJSON(URL, parentProperties); e.g:
// importEntitiesJSON('https://www.acme.com/example/cubes.json', {position: MyAvatar.position})
var IMPORT_ENTITIES = [
];
// Mainly for importing creation scripts (that contain hold/sprint or any other actions)
// Make sure that the scripts that are put here do not Script.stop() or leave in any timers/event handlers
// If you really want to listen to events or have a timer, then you could make the scripts events/timer stop after a specific item that was created in the script gets cleaned up
var IMPORT_SCRIPTS = [
];
var CLEANUP_AUDIO_TRACKS_PREFIX = 'http://hifi-content.s3.amazonaws.com/DomainContent/Welcome%20Area/Sounds/';
var WELCOME_WAGON_AUDIO_TRACKS_PREFIX = 'http://content.highfidelity.com/DomainContent/production/welcomeWagon/sfx/';
var CLEANUP_AUDIO_BROADCAST_POSITIONS = [
{x: 431.0, y: 515.0, z: 494.0}
];
// No properties set at the moment.
var CLEANUP_AUDIO_BROADCAST_PROPERTIES = {
volume: 1.1
};
// These times MUST be in RUN_WHEN too
var WELCOME_WAGON_DEPART_TIMES = [
'9:00',
'21:00'
];
var CLEANUP_AUDIO_TRACKS = [];
// Constants
var HOURS_IN_DAY = 24;
var MINUTES_IN_HOUR = 60;
var SECONDS_PER_MINUTE = 60;
var MILLISECONDS_PER_SECOND = 1000;
var MINUTES_IN_DAY = HOURS_IN_DAY * MINUTES_IN_HOUR;
var TIMER_TICKS_PER_MINUTE = SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND;
var ZERO_UUID = '{00000000-0000-0000-0000-000000000000}';
var CLEANUP_TIMEBLOCK_IN_MIN = (MINUTES_IN_HOUR * 2) - 1;
var adminSessions = [];
RUN_WHEN.forEach(function(runTime) {
var runTimeMins = timeStringToMinutesInDay(runTime);
var startTime = runTime;
var endTime = minutesInDayToTimeString(runTimeMins + CLEANUP_TIMEBLOCK_IN_MIN);
if (WELCOME_WAGON_DEPART_TIMES.indexOf(runTime) !== -1) {
CLEANUP_AUDIO_TRACKS.push(
{
name: 'welcomeWagon_FiveMin_' + runTime,
url: WELCOME_WAGON_AUDIO_TRACKS_PREFIX + 'five_min.wav',
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -300,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
},
{
name: 'welcomeWagon_OneMin_' + runTime,
url: WELCOME_WAGON_AUDIO_TRACKS_PREFIX + 'one_min.wav',
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -60,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
},
{
name: 'welcomeWagon_countdown_' + runTime,
url: WELCOME_WAGON_AUDIO_TRACKS_PREFIX + 'countdown.wav',
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -9.7,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
},
{
name: 'welcomeWagon_transport_' + runTime,
url: WELCOME_WAGON_AUDIO_TRACKS_PREFIX + 'gravity_trap_bip_1.wav',
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -1.7,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
}
);
} else {
var oneMinClip;
var hour = (runTimeMins % MINUTES_IN_HOUR) % HOURS_IN_DAY;
if (hour >= 0 && hour < 11) {
oneMinClip = 'VOGGoodMorning_OneMin.wav';
} else if (hour >= 12 && hour < 17) {
oneMinClip = 'VOGGoodAfternoon_OneMin.wav';
} else {
oneMinClip = 'VOGGoodEvening_OneMin.wav';
}
CLEANUP_AUDIO_TRACKS.push(
{
name: 'good_evening_' + runTime,
url: CLEANUP_AUDIO_TRACKS_PREFIX + oneMinClip,
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -60,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
},
{
name: 'countdown_' + runTime,
url: CLEANUP_AUDIO_TRACKS_PREFIX + 'VOGCountdown.wav',
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -8.7,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
},
{
name: 'five_minutes_warning_' + runTime,
url: CLEANUP_AUDIO_TRACKS_PREFIX + 'VOGFiveMin.wav',
startTime: startTime,
endTime: endTime,
cleanupOffsetSeconds: -300,
broadcastPositions: CLEANUP_AUDIO_BROADCAST_POSITIONS,
properties: CLEANUP_AUDIO_BROADCAST_PROPERTIES
}
);
}
});
// You can use DRY RUN mode to test the cleanup filter and see which entities will be
// deleted without modifying anything
var DRY_RUN = false;
var SEARCH_CENTER = {x: 19.2, y: 0.1, z: -135.6};
var SEARCH_AREA = 60000; // search area (sphere) in meters radius
// Allows you to manually trigger the cleanups through the messages system
var REMOTE_TRIGGER_ENABLED = true;
var TRIGGER_CHANNEL = 'cleanUpAndSpawnBot';
var CLEAN_MESSAGE = 'cleanUp';
var SPAWN_MESSAGE = 'spawn';
var CLEAN_AND_SPAWN_MESSAGE = 'cleanUpAndSpawn';
var DEBUG_SCRIPT_OVER_CHANNEL = '';
var SANETIZE_PROPERTIES = ['childEntities', 'parentID', 'id'];
function preloadCleanupAudioTracks() {
CLEANUP_AUDIO_TRACKS.forEach(function(cleanupAudioTrack) {
cleanupAudioTrack.sound = SoundCache.getSound(cleanupAudioTrack.url);
});
}
function isCorrectPlace() {
return location !== undefined && location.hostname === PLACENAME_LOCK;
}
var debug = function(message) {
print(message);
if (DEBUG_SCRIPT_OVER_CHANNEL !== '') {
Messages.sendMessage(DEBUG_SCRIPT_OVER_CHANNEL, message);
}
};
function entityListToTree(entitiesList) {
function entityListToTreeRecursive(properties) {
properties.childEntities = [];
entitiesList.forEach(function(entityProperties) {
if (properties.id === entityProperties.parentID) {
properties.childEntities.push(entityListToTreeRecursive(entityProperties));
}
});
return properties;
}
var entityTree = [];
entitiesList.forEach(function(entityProperties) {
if (entityProperties.parentID === undefined || entityProperties.parentID === ZERO_UUID) {
entityTree.push(entityListToTreeRecursive(entityProperties));
}
});
return entityTree;
}
function importEntitiesJSON(importLink, parentProperties, overrideProperties) {
if (parentProperties === undefined) {
parentProperties = {};
}
if (overrideProperties !== undefined) {
parentProperties.overrideProperties = overrideProperties;
}
try {
parentProperties.childEntities = entityListToTree(Script.require(importLink).Entities);
return parentProperties;
} catch (e) {
debug('Failed importing entities JSON because: ' + JSON.stringify(e));
}
return null;
}
function importScript(importScript, properties) {
var request = new XMLHttpRequest();
request.open('GET', importScript, false);
request.send();
return {script: request.responseText, properties: properties};
}
// Creates an entity and returns a mixed object of the creation properties and the assigned entityID
var createEntity = function(entityProperties, parent, overrideProperties) {
// JSON.stringify -> JSON.parse trick to create a fresh copy of JSON data
var newEntityProperties = JSON.parse(JSON.stringify(entityProperties));
if (overrideProperties !== undefined) {
Object.keys(overrideProperties).forEach(function(key) {
newEntityProperties[key] = overrideProperties[key];
});
}
if (parent.rotation !== undefined) {
if (newEntityProperties.rotation !== undefined) {
newEntityProperties.rotation = Quat.multiply(parent.rotation, newEntityProperties.rotation);
} else {
newEntityProperties.rotation = parent.rotation;
}
}
if (parent.position !== undefined) {
var localPosition = (parent.rotation !== undefined) ?
Vec3.multiplyQbyV(parent.rotation, newEntityProperties.position) : newEntityProperties.position;
newEntityProperties.position = Vec3.sum(localPosition, parent.position);
}
if (parent.id !== undefined) {
newEntityProperties.parentID = parent.id;
}
newEntityProperties.id = Entities.addEntity(newEntityProperties);
return newEntityProperties;
};
var createEntitiesFromTree = function(entityTree, parent, overrideProperties) {
if (parent === undefined) {
parent = {};
}
if (parent.overrideProperties !== undefined) {
overrideProperties = parent.overrideProperties;
}
var createdTree = [];
entityTree.forEach(function(entityProperties) {
var sanetizedProperties = {};
Object.keys(entityProperties).forEach(function(propertyKey) {
if (!entityProperties.hasOwnProperty(propertyKey) || SANETIZE_PROPERTIES.indexOf(propertyKey) !== -1) {
return true;
}
sanetizedProperties[propertyKey] = entityProperties[propertyKey];
});
// Allow for non-entity parent objects, this allows us to offset groups of entities to a specific position/rotation
var parentProperties = sanetizedProperties;
if (entityProperties.type !== undefined) {
parentProperties = createEntity(sanetizedProperties, parent, overrideProperties);
}
if (entityProperties.childEntities !== undefined) {
parentProperties.childEntities =
createEntitiesFromTree(entityProperties.childEntities, parentProperties, overrideProperties);
}
createdTree.push(parentProperties);
});
return createdTree;
};
function playCleanupAudioTrack(audioTrack) {
debug('Playing audio track: ' + audioTrack.name);
audioTrack.broadcastPositions.forEach(function(broadcastPosition) {
var properties = audioTrack.properties;
properties.position = broadcastPosition;
Audio.playSound(audioTrack.sound, properties);
});
}
function timeStringToMinutesInDay(timeText) {
try {
var timeArray = timeText.split(':');
var hour = parseInt(timeArray[0]);
var minute = parseInt(timeArray[1]);
return (MINUTES_IN_HOUR * hour) + minute;
} catch (e) {
debug('Had some trouble while parsing the following time: ' + timeText);
}
return -1;
}
function minutesInDayToTimeString(minutes) {
var hour = Math.floor(minutes / MINUTES_IN_HOUR) % HOURS_IN_DAY;
var minute = minutes % MINUTES_IN_HOUR;
if (minute < 10) {
return hour + ':0' + minute;
}
return hour + ':' + minute;
}
function getCurrentMinuteInDay() {
var now = new Date();
var currentMinuteInDay = (MINUTES_IN_HOUR * now.getUTCHours()) + now.getUTCMinutes();
return currentMinuteInDay;
}
function getTimeUntilNextRun(times) {
var parsedTimes = [];
var currentMinuteInDay = getCurrentMinuteInDay();
times.forEach(function(timeText) {
var minuteInDay = timeStringToMinutesInDay(timeText);
var minutesToNextRun = minuteInDay - currentMinuteInDay + (minuteInDay <= currentMinuteInDay ? MINUTES_IN_DAY : 0);
parsedTimes.push({
timeText: timeText,
timerTicksUntilNextRun: TIMER_TICKS_PER_MINUTE * minutesToNextRun,
minuteInDay: minuteInDay,
minutesToNextRun: minutesToNextRun
});
});
var lowestParsedTime = null;
parsedTimes.forEach(function(parsedTime) {
if (lowestParsedTime === null || parsedTime.minutesToNextRun < lowestParsedTime.minutesToNextRun) {
lowestParsedTime = parsedTime;
}
});
if (lowestParsedTime === null) {
debug('Something went wrong while retrieving the next run time.');
return null;
}
return lowestParsedTime;
}
function triggerEventOn(times, callback) {
var parsedNextRunTime = getTimeUntilNextRun(times);
var timeout = parsedNextRunTime.timerTicksUntilNextRun;
debug('Set timeout to ' + timeout + ' ms.');
Script.setTimeout(callback, timeout);
return parsedNextRunTime;
}
function planAudioForCleanupEvent(nextCleanupParsedTime) {
CLEANUP_AUDIO_TRACKS.forEach(function(audioTrack) {
var startTimeMinutes = timeStringToMinutesInDay(audioTrack.startTime);
var endTimeMinutes = timeStringToMinutesInDay(audioTrack.endTime);
debug(startTimeMinutes + ' ' + endTimeMinutes);
if (startTimeMinutes <= nextCleanupParsedTime.minuteInDay && endTimeMinutes >= nextCleanupParsedTime.minuteInDay) {
debug('Planned to play ' + audioTrack.name + ' for the next scheduled cleanup');
var timerTicksUntilNextRun = nextCleanupParsedTime.timerTicksUntilNextRun + (audioTrack.cleanupOffsetSeconds * MILLISECONDS_PER_SECOND);
Script.setTimeout(function() {
playCleanupAudioTrack(audioTrack);
}, timerTicksUntilNextRun);
}
});
}
function setupNextCleanupAndAudioEvent() {
var nextCleanupParsedTime = triggerEventOn(RUN_WHEN, doCleanup);
planAudioForCleanupEvent(nextCleanupParsedTime);
}
var doCleanup = function() {
debug('Doing Cleanup and Spawn.');
purgeEntities();
importEntities();
importScripts();
setupNextCleanupAndAudioEvent();
};
var testFilter = function(filter, properties) {
var testFilter = typeof(filter) === 'object' ? filter : {name: filter};
for (var key in testFilter) {
if (!testFilter.hasOwnProperty(key)) {
continue;
}
if (testFilter[key] !== properties[key]) {
return false;
}
}
return true;
};
var purgeEntities = function() {
if (!Script.isAgentScript() && !isCorrectPlace()) {
debug('The PLACENAME_LOCK does not match the current placename, aborting purgeEntities.');
return;
}
var propertiesToRequest = ['name'];
CLEANUP_FILTER.forEach(function(filter) {
if (typeof(filter) === 'object') {
Object.keys(filter).forEach(function(property) {
if (propertiesToRequest.indexOf(property) === -1) {
propertiesToRequest.push(property);
}
});
}
});
Entities.findEntities(SEARCH_CENTER, SEARCH_AREA).forEach(function(entityID) {
var entityProperties = Entities.getEntityProperties(entityID, propertiesToRequest);
var deleteEntity = false;
CLEANUP_FILTER.forEach(function(filter) {
if (testFilter(filter, entityProperties)) {
deleteEntity = true;
return true;
}
});
if (deleteEntity) {
debug(DRY_RUN ? '[DRY_RUN] Would have removed: ' : 'removing: ' + entityProperties.id + ' ' +
entityProperties.name);
if (!DRY_RUN) {
Entities.deleteEntity(entityProperties.id);
}
}
});
};
var importScripts = function() {
if (DRY_RUN) {
debug('Skipping importScripts for the DRY_RUN.');
return {};
}
if (!Script.isAgentScript() && !isCorrectPlace()) {
debug('The PLACENAME_LOCK does not match the current placename, aborting importEntities.');
return {};
}
IMPORT_SCRIPTS.forEach(function(importScript) {
// eslint-disable-next-line no-unused-vars
var SCRIPT_IMPORT_PROPERTIES = importScript.properties;
this.isCleanupAndSpawnScript = true;
eval(importScript.script);
});
};
var importEntities = function() {
if (DRY_RUN) {
debug('Skipping importEntities for the DRY_RUN.');
return {};
}
if (!Script.isAgentScript() && !isCorrectPlace()) {
debug('The PLACENAME_LOCK does not match the current placename, aborting importEntities.');
return {};
}
return createEntitiesFromTree(IMPORT_ENTITIES);
};
preloadCleanupAudioTracks();
setupNextCleanupAndAudioEvent();
if (REMOTE_TRIGGER_ENABLED) {
Messages.messageReceived.connect(function(channel, message, senderUUID, localOnly) {
if (channel !== TRIGGER_CHANNEL) {
return;
}
if (adminSessions.indexOf(senderUUID) === -1) {
debug('sender ' + senderUUID + ' is not an admin, message: ' + message);
return;
}
if (message === CLEAN_MESSAGE || message === CLEAN_AND_SPAWN_MESSAGE) {
purgeEntities();
}
if (message === SPAWN_MESSAGE || message === CLEAN_AND_SPAWN_MESSAGE) {
importEntities();
importScripts();
}
try {
var data = JSON.parse(message);
if (data.action === 'debug_cleanupTrack') {
CLEANUP_AUDIO_TRACKS.forEach(function(cleanupTrack) {
if (data.name === cleanupTrack.name) {
playCleanupAudioTrack(cleanupTrack);
}
});
} else if (data.action === 'debug_listCleanupTracks') {
CLEANUP_AUDIO_TRACKS.forEach(function(cleanupTrack) {
print(cleanupTrack.name);
});
}
} catch (e) {
// e
}
});
Messages.subscribe(TRIGGER_CHANNEL);
}
// Assignment Client related code:
if (Script.isAgentScript()) {
Agent.isAvatar = true;
Avatar.skeletonModelURL = 'http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst';
Avatar.displayName = DISPLAY_NAME;
var initialized = false;
var update = function(deltaTime) {
if (!initialized) {
if (Entities.serversExist() && Entities.canRez()) {
Entities.setPacketsPerSecond(60000);
EntityViewer.setPosition(SEARCH_CENTER);
EntityViewer.setCenterRadius(SEARCH_AREA);
// This should allow us to see nano-scale entities from great distances
EntityViewer.setVoxelSizeScale(Number.MAX_VALUE);
Script.setInterval(function() {
EntityViewer.queryOctree();
}, 1000);
initialized = true;
Script.update.disconnect(update);
}
return;
}
};
Script.update.connect(update);
AvatarList.avatarAddedEvent.connect(function(avatarID) {
if (avatarID === Agent.sessionUUID) {
debug('Skipping own session UUID ' + avatarID);
return;
}
debug('Requesting ' + avatarID);
// Test
var IDENTITY_PACKETS_TIMEOUT = 1000;
Script.setTimeout(function() {
Users.requestUsernameFromID(avatarID);
}, IDENTITY_PACKETS_TIMEOUT);
});
AvatarList.avatarAddedEvent.connect(function(avatarID) {
var adminSessionsIndex = adminSessions.indexOf(avatarID);
if (adminSessionsIndex !== -1) {
adminSessions.splice(adminSessionsIndex, 1);
}
});
Users.usernameFromIDReply.connect(function(id, username, machineFingerprint, isAdmin) {
if (!isAdmin) {
Users.ignore(id, true);
debug(username + " " + id + " is NOT supposed to see me.");
} else {
if (adminSessions.indexOf(id) === -1) {
adminSessions.push(id);
}
debug(username + " " + id + " is supposed to see me.");
}
});
}