253 lines · 8.3 KB · JavaScript
RawDownload
"use strict";////  mod.js//  scripts/system/////  Created by Stephen Birarda on July 11th, 2016//  Copyright 2016 High Fidelity, Inc.//  Copyright 2023 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html///* global Toolbars, Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */ (function() { // BEGIN LOCAL_SCOPE Script.include("/~/system/libraries/controllers.js"); var controllerStandard = Controller.Standard; // grab the toolbarvar tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var ASSETS_PATH = Script.resolvePath("assets");var TOOLS_PATH = Script.resolvePath("assets/images/tools/"); function buttonImageURL() {    return (Users.canKick ? "kick.svg" : "ignore.svg");} // setup the mod button and add it to the toolbarvar button = tablet.addButton({    icon: "icons/tablet-icons/ignore-i.svg",    text: "KICK"}); // if this user's kick permissions change, change the state of the button in the HUDUsers.canKickChanged.connect(function(canKick){    button.editProperties({text: buttonImageURL()});}); var isShowingOverlays = false;var modOverlays = {}; function removeOverlays() {    // enumerate the overlays and remove them    var modOverlayKeys = Object.keys(modOverlays);     for (var i = 0; i < modOverlayKeys.length; ++i) {        var avatarID = modOverlayKeys[i];        for (var j = 0; j < modOverlays[avatarID].length; ++j) {            Entities.deleteEntity(modOverlays[avatarID][j]);        }    }     modOverlays = {};} // handle clicks on the toolbar buttonfunction buttonClicked(){    if (isShowingOverlays) {        removeOverlays();        isShowingOverlays = false;    } else {        isShowingOverlays = true;    }  } button.clicked.connect(buttonClicked); function kickOverlayURL() {    return ASSETS_PATH + "/images/" + (Users.canKick ? "kick-target.svg" : "ignore-target.svg");} function muteOverlayURL() {    return ASSETS_PATH + "/images/" + "mute-target.svg";} function updateOverlays() {    if (isShowingOverlays) {         var identifiers = AvatarList.getAvatarIdentifiers();         for (var i = 0; i < identifiers.length; ++i) {            var avatarID = identifiers[i];             if (avatarID === null) {                // this is our avatar, skip it                continue;            }             // get the position for this avatar            var avatar = AvatarList.getAvatar(avatarID);            var avatarPosition = avatar && avatar.position;             if (!avatarPosition) {                // we don't have a valid position for this avatar, skip it                continue;            }             // setup a position for the overlay that is just above this avatar's head            var kickOverlayPosition = avatar.getJointPosition("Head");            kickOverlayPosition.y += 0.45;            var muteOverlayPosition = avatar.getJointPosition("Head");            muteOverlayPosition.y += 0.70;             if (avatarID in modOverlays) {                // keep the overlay above the current position of this avatar                Entities.editEntity(modOverlays[avatarID][0], {                    "position": kickOverlayPosition,                    "imageURL": kickOverlayURL()                });                if (Users.canKick) {                    Entities.editEntity(modOverlays[avatarID][1], {                        "position": muteOverlayPosition,                        "imageURL": muteOverlayURL()                    });                }            } else {                // add the overlay above this avatar                var newKickOverlay = Entities.addEntity({                    "type": "Image",                    "imageURL": kickOverlayURL(),                    "position": kickOverlayPosition,                    "dimensions": { "x": 0.4, "y": 0.4, "z": 0.4},                    "color": { "red": 255, "green": 255, "blue": 255},                    "alpha": 1,                    "primitiveMode": "solid",                    "billboardMode": "full",                    "renderLayer": "front"                }, "local");                 modOverlays[avatarID]=[newKickOverlay];                 if (Users.canKick) {                    var newMuteOverlay = Entities.addEntity({                        "type": "Image",                        "imageURL": muteOverlayURL(),                        "position": muteOverlayPosition,                        "dimensions": { "x": 0.4, "y": 0.4, "z": 0.4},                        "color": { "red": 255, "green": 255, "blue": 255},                        "alpha": 1,                        "primitiveMode": "solid",                        "billboardMode": "full",                        "renderLayer": "front"                    }, "local");                    // push this overlay to our array of overlays                    modOverlays[avatarID].push(newMuteOverlay);                }            }        }    }} Script.update.connect(updateOverlays); AvatarList.avatarRemovedEvent.connect(function(avatarID){    if (isShowingOverlays) {        // we are currently showing overlays and an avatar just went away         // first remove the rendered overlays        for (var j = 0; j < modOverlays[avatarID].length; ++j) {            Entities.deleteEntity(modOverlays[avatarID][j]);        }                // delete the saved ID of the overlay from our mod overlays object        delete modOverlays[avatarID];    }}); function handleSelectedOverlay(clickedOverlay) {    // see this is one of our mod overlays     var modOverlayKeys = Object.keys(modOverlays);    for (var i = 0; i < modOverlayKeys.length; ++i) {        var avatarID = modOverlayKeys[i];        var modOverlay = modOverlays[avatarID][0];        var muteOverlay = modOverlays[avatarID][1];         if (clickedOverlay.overlayID == modOverlay) {            // matched to an overlay, ask for the matching avatar to be kicked or ignored            if (Users.canKick) {                Users.kick(avatarID);            } else {                Users.ignore(avatarID);            }            // cleanup of the overlay is handled by the connection to avatarRemovedEvent         } else if (muteOverlay && clickedOverlay.overlayID == muteOverlay) {            Users.mute(avatarID);        }    }} Controller.mousePressEvent.connect(function(event){    if (isShowingOverlays) {        // handle click events so we can detect when our overlays are clicked         if (!event.isLeftButton) {            // if another mouse button than left is pressed ignore it            return false;        }         // compute the pick ray from the event        var pickRay = Camera.computePickRay(event.x, event.y);         // grab the clicked overlay for the given pick ray        var clickedOverlay = Overlays.findRayIntersection(pickRay);        if (clickedOverlay.intersects) {            handleSelectedOverlay(clickedOverlay);        }    }}); // We get mouseMoveEvents from the handControllers, via handControllerPointer.// But we dont' get mousePressEvents.var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); function controllerComputePickRay(hand) {    var controllerPose = getControllerWorldLocation(hand, true);    if (controllerPose.valid) {        return { origin: controllerPose.position, direction: Quat.getUp(controllerPose.orientation) };    }} function makeClickHandler(hand) {    return function(clicked) {        if (clicked == 1.0 && isShowingOverlays) {            var pickRay = controllerComputePickRay(hand);            if (pickRay) {                var overlayIntersection = Overlays.findRayIntersection(pickRay);                if (overlayIntersection.intersects) {                    handleSelectedOverlay(overlayIntersection);                }            }        }    };}triggerMapping.from(controllerStandard.RTClick).peek().to(makeClickHandler(controllerStandard.RightHand));triggerMapping.from(controllerStandard.LTClick).peek().to(makeClickHandler(controllerStandard.LeftHand)); triggerMapping.enable(); // cleanup the toolbar button and overlays when script is stoppedScript.scriptEnding.connect(function() {    tablet.removeButton(button);    removeOverlays();    triggerMapping.disable();}); }()); // END LOCAL_SCOPE