// // renderWithZonesManager.js // // Created by Alezia Kurdis on January 28th, 2024. // Copyright 2024 Overte e.V. // // This script is to manage the zone in the property renderWithZones more efficiently in the Create Application. // It allows a global view over a specific selection with possibility to // REPLACE, REMOVE or ADD zones on those properties more efficiently. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // let rwzmSelectedId = []; let rwzmAllZonesList = []; let rwzmUsedZonesList = []; let rwzmSelectedEntitiesData = []; let rwzmUndo = []; let enforceLocked = false; const RWZ_ZONE_SCAN_RADIUS = 27713; //maximal radius to cover the entire domain. let rwzmOverlayWebWindow = null; function renderWithZonesManager(entityIDs, highlightedID = "") { if (rwzmGetCheckSum(entityIDs) !== rwzmGetCheckSum(rwzmSelectedId)) { rwzmUndo = []; } rwzmSelectedId = entityIDs; if (entityIDs.length === 0) { audioFeedback.rejection(); Window.alert("You have nothing selected."); return; } else { rwzmAllZonesList = []; rwzmUsedZonesList = []; rwzmSelectedEntitiesData = []; rwzmAllZonesList = rwzmGetExistingZoneList(); let properties; let i = 0; let j = 0; let rwzmData = {}; for (i = 0; i < entityIDs.length; i++ ){ properties = Entities.getEntityProperties(entityIDs[i], ["renderWithZones", "locked", "name", "type"]); //Identify the unique zone used in renderWithZones properties of the entities and make the list of this in rwzmUsedZonesList if (properties.renderWithZones.length > 0) { for (j = 0; j < properties.renderWithZones.length; j++ ){ if (rwzmUsedZonesList.indexOf(properties.renderWithZones[j]) === -1) { rwzmUsedZonesList.push(properties.renderWithZones[j]); } } } //Make the list of entities, with their id, renderWithZones, locked, in rwzmSelectedEntitiesData rwzmData = { "id": entityIDs[i], "name": properties.name, "type": properties.type, "renderWithZones": properties.renderWithZones, "locked": properties.locked }; rwzmSelectedEntitiesData.push(rwzmData); } } if (rwzmOverlayWebWindow === null) { rwzmOverlayWebWindow = new OverlayWebWindow({ title: "RenderWithZones Manager", source: Script.resolvePath("renderWithZonesManager.html"), width: 1100, height: 600 }); rwzmOverlayWebWindow.closed.connect(uiHasClosed); rwzmOverlayWebWindow.webEventReceived.connect(webEventReceiver); } rwzmGenerateUI(highlightedID); } function rwzmGetCheckSum(array) { let i = 0; let sum = 0; let strForm = JSON.stringify(array); for (i = 0; i < strForm.length; i++) { sum = sum + strForm.charCodeAt(i); } return sum; } function uiHasClosed() { rwzmOverlayWebWindow.closed.disconnect(uiHasClosed); rwzmOverlayWebWindow.webEventReceived.disconnect(webEventReceiver); rwzmOverlayWebWindow = null; } function rwzmGenerateUI(highlightedID) { let canUnlock = Entities.canAdjustLocks(); let uiContent = ""; let i = 0; let k = 0; let zones = ""; let name = ""; let elementClass = ""; let firstClass = ""; let isLocked = ""; let selectionBox = ""; let setCheck = ""; let addAction = ""; let toHighlight = ""; let viewBtnCaption = ""; let warning = false; uiContent = uiContent + '

RenderWithZones Manager


\n'; if (canUnlock) { if (enforceLocked) { setCheck = " checked"; } else { setCheck = ""; } } uiContent = uiContent + ' \n'; uiContent = uiContent + ' \n'; uiContent = uiContent + ' \n'; uiContent = uiContent + ' \n'; uiContent = uiContent + ' \n'; uiContent = uiContent + ' \n'; uiContent = uiContent + '
\n'; if (rwzmUndo.length === 0) { undoBtnCode = ""; } else { undoBtnCode = ''; } uiContent = uiContent + '

Visibility Zones:

' + undoBtnCode + '
\n'; uiContent = uiContent + '
\n'; uiContent = uiContent + ' \n'; for (i = 0; i < rwzmUsedZonesList.length; i++ ) { name = rwzmGetZoneName(rwzmUsedZonesList[i]); elementClass = "line"; firstClass = "cells"; if (name === "") { name = rwzmGenerateUnidentifiedZoneName(rwzmUsedZonesList[i]); elementClass = "errorline"; warning = true; } toHighlight = rwzmUsedZonesList[i]; viewBtnCaption = "View"; if ( rwzmUsedZonesList[i] === highlightedID) { toHighlight = ""; viewBtnCaption = "Hide"; firstClass = "highlightedCells"; if (elementClass === "line") { elementClass = "lineInverted"; } } uiContent = uiContent + ' \n'; } uiContent = uiContent + '
'; uiContent = uiContent + 'ZONESACTIONS (On listed entities)
' + rwzmGetTruncatedString(name, 30) + '
'; uiContent = uiContent + ''; uiContent = uiContent + ''; uiContent = uiContent + '
\n'; uiContent = uiContent + '
 \n'; uiContent = uiContent + ' '; uiContent = uiContent + '

Entities:

Modify locked entities for me.
\n'; uiContent = uiContent + '
\n'; uiContent = uiContent + ' \n'; for (i = 0; i < rwzmSelectedEntitiesData.length; i++ ) { elementClass = "line"; firstClass = "cells"; if (rwzmSelectedEntitiesData[i].renderWithZones.indexOf(highlightedID) !== -1) { firstClass = "highlightedCells"; elementClass = "lineInverted"; } zones = " "; if (rwzmSelectedEntitiesData[i].renderWithZones.length > 0) { for (k = 0; k < rwzmSelectedEntitiesData[i].renderWithZones.length; k++ ) { name = rwzmGetTruncatedString(rwzmGetZoneName(rwzmSelectedEntitiesData[i].renderWithZones[k]),30); if (name === "") { name = rwzmGetTruncatedString(rwzmGenerateUnidentifiedZoneName(rwzmSelectedEntitiesData[i].renderWithZones[k]),30); } if ((canUnlock && enforceLocked && rwzmSelectedEntitiesData[i].locked) || !rwzmSelectedEntitiesData[i].locked) { name = name + " "; } if (k === 0) { zones = zones + name; } else { zones = zones + "
" + name; } } } isLocked = " "; selectionBox = " "; addAction = " "; if ((canUnlock && enforceLocked && rwzmSelectedEntitiesData[i].locked) || !rwzmSelectedEntitiesData[i].locked) { addAction = ""; selectionBox = ''; } if (rwzmSelectedEntitiesData[i].locked) { if (canUnlock) { isLocked = ""; //Locked } else { isLocked = "🛇"; //Forbidden } } uiContent = uiContent + ' \n'; } uiContent = uiContent + '
'; uiContent = uiContent + ''; uiContent = uiContent + 'ENTITIES'; uiContent = uiContent + 'RENDER WITH ZONES 
' + selectionBox; uiContent = uiContent + '' + isLocked + '' + rwzmSelectedEntitiesData[i].type + ' - ' + rwzmGetTruncatedString(rwzmSelectedEntitiesData[i].name, 30) + '' + zones + '' + addAction + '
\n'; uiContent = uiContent + '
\n'; uiContent = uiContent + ' \n'; if (warning) { uiContent = uiContent + '
WARNING: The "ZONE NOT FOUND" visibility zones might simply not be loaded if too far and small. Please, verify before.
\n'; } //Zone selector Add uiContent = uiContent + '
\n'; uiContent = uiContent + '

Select the zone to add:

\n'; for (i = 0; i < rwzmAllZonesList.length; i++ ) { uiContent = uiContent + "
\n"; } uiContent = uiContent + '
\n'; uiContent = uiContent + '
\n'; //Zone selector Replace uiContent = uiContent + '
\n'; uiContent = uiContent + '

Select the replacement zone:

\n'; for (i = 0; i < rwzmAllZonesList.length; i++ ) { uiContent = uiContent + "
\n"; } uiContent = uiContent + '
\n'; uiContent = uiContent + '
\n'; Script.setTimeout(function () { rwzmOverlayWebWindow.emitScriptEvent(uiContent); }, 300); } function rwzmGetZoneName(id) { let k = 0; let name = ""; for (k = 0; k < rwzmAllZonesList.length; k++) { if (rwzmAllZonesList[k].id === id) { name = rwzmAllZonesList[k].name; break; } } return name; } function rwzmGenerateUnidentifiedZoneName(id) { let partialID = id.substr(1,8); return "ZONE NOT FOUND (" + partialID +")"; } function rwzmGetExistingZoneList() { var center = { "x": 0, "y": 0, "z": 0 }; var existingZoneIDs = Entities.findEntitiesByType("Zone", center, RWZ_ZONE_SCAN_RADIUS); var listExistingZones = []; var thisZone = {}; var properties; for (var k = 0; k < existingZoneIDs.length; k++) { properties = Entities.getEntityProperties(existingZoneIDs[k], ["name"]); thisZone = { "id": existingZoneIDs[k], "name": properties.name }; listExistingZones.push(thisZone); } listExistingZones.sort(rwzmZoneSortOrder); return listExistingZones; } function rwzmZoneSortOrder(a, b) { var nameA = a.name.toUpperCase(); var nameB = b.name.toUpperCase(); if (nameA > nameB) { return 1; } else if (nameA < nameB) { return -1; } if (a.name > b.name) { return 1; } else if (a.name < b.name) { return -1; } return 0; } function rwzmRemoveZoneFromEntity(id, zoneID, forceLocked, highlightedID) { rwzmUndo = []; let properties = Entities.getEntityProperties(id, ["renderWithZones", "locked"]); let newRenderWithZones = []; let i = 0; for (i = 0; i < properties.renderWithZones.length; i++) { if (properties.renderWithZones[i] !== zoneID) { newRenderWithZones.push(properties.renderWithZones[i]); } } if (forceLocked && properties.locked) { Entities.editEntity(id, {"locked": false}); Entities.editEntity(id, {"renderWithZones": newRenderWithZones, "locked": properties.locked}); } else { Entities.editEntity(id, {"renderWithZones": newRenderWithZones}); } rwzmUndo.push({"id": id, "renderWithZones": properties.renderWithZones}); renderWithZonesManager(rwzmSelectedId, highlightedID); } function rwzmAddZonesToEntities(ids, zoneID, forceLocked, highlightedID) { rwzmUndo = []; let k = 0; let j = 0; let properties; let newRenderWithZones = []; for (k = 0; k < ids.length; k++) { properties = Entities.getEntityProperties(ids[k], ["renderWithZones", "locked"]); newRenderWithZones = []; for (j = 0; j < properties.renderWithZones.length; j++) { if (properties.renderWithZones[j] !== zoneID) { newRenderWithZones.push(properties.renderWithZones[j]); } } newRenderWithZones.push(zoneID); if (forceLocked && properties.locked) { Entities.editEntity(ids[k], {"locked": false}); Entities.editEntity(ids[k], {"renderWithZones": newRenderWithZones, "locked": properties.locked}); } else { Entities.editEntity(ids[k], {"renderWithZones": newRenderWithZones}); } rwzmUndo.push({"id": ids[k], "renderWithZones": properties.renderWithZones}); } renderWithZonesManager(rwzmSelectedId, highlightedID); } function rwzmRemoveZoneFromAllEntities(zoneID, forceLocked, highlightedID) { rwzmUndo = []; let k = 0; let j = 0; let properties; let newRenderWithZones = []; for (k = 0; k < rwzmSelectedId.length; k++) { properties = Entities.getEntityProperties(rwzmSelectedId[k], ["renderWithZones", "locked"]); newRenderWithZones = []; for (j = 0; j < properties.renderWithZones.length; j++) { if (properties.renderWithZones[j] !== zoneID) { newRenderWithZones.push(properties.renderWithZones[j]); } } if (forceLocked && properties.locked) { Entities.editEntity(rwzmSelectedId[k], {"locked": false}); Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones, "locked": properties.locked}); } else { Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones}); } rwzmUndo.push({"id": rwzmSelectedId[k], "renderWithZones": properties.renderWithZones}); } renderWithZonesManager(rwzmSelectedId, highlightedID); } function rwzmReplaceZoneOnAllEntities(targetZoneID, replacementZoneID, forceLocked, highlightedID) { rwzmUndo = []; let k = 0; let j = 0; let properties; let newRenderWithZones = []; for (k = 0; k < rwzmSelectedId.length; k++) { properties = Entities.getEntityProperties(rwzmSelectedId[k], ["renderWithZones", "locked"]); newRenderWithZones = []; for (j = 0; j < properties.renderWithZones.length; j++) { if (properties.renderWithZones[j] !== targetZoneID) { newRenderWithZones.push(properties.renderWithZones[j]); } else { newRenderWithZones.push(replacementZoneID); } } if (forceLocked && properties.locked) { Entities.editEntity(rwzmSelectedId[k], {"locked": false}); Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones, "locked": properties.locked}); } else { Entities.editEntity(rwzmSelectedId[k], {"renderWithZones": newRenderWithZones}); } rwzmUndo.push({"id": rwzmSelectedId[k], "renderWithZones": properties.renderWithZones}); } renderWithZonesManager(rwzmSelectedId, highlightedID); } function rwzmGetTruncatedString(str, max) { if (str.length > max) { return str.substr(0, max-1) + "…"; } else { return str; } } function rwzmUndoLastAction(highlightedID) { let k = 0; let properties; let locked; for (k = 0; k < rwzmUndo.length; k++) { locked = Entities.getEntityProperties(rwzmUndo[k].id, ["locked"]).locked; if (locked) { Entities.editEntity(rwzmUndo[k].id, {"locked": false}); Entities.editEntity(rwzmUndo[k].id, {"renderWithZones": rwzmUndo[k].renderWithZones, "locked": locked}); } else { Entities.editEntity(rwzmUndo[k].id, {"renderWithZones": rwzmUndo[k].renderWithZones}); } } rwzmUndo = []; renderWithZonesManager(rwzmSelectedId, highlightedID); } function webEventReceiver (message) { try { var data = JSON.parse(message); } catch(e) { print("renderWithZonesManager.js: Error parsing JSON"); return; } if (data.action === "highlight") { enforceLocked = data.enforceLocked; renderWithZonesManager(rwzmSelectedId, data.id); } else if (data.action === "removeZoneFromEntity") { enforceLocked = data.enforceLocked; rwzmRemoveZoneFromEntity(data.id, data.zoneID, data.enforceLocked, data.highlightedID); } else if (data.action === "addZoneToEntities") { enforceLocked = data.enforceLocked; rwzmAddZonesToEntities(data.ids, data.zoneID, data.enforceLocked, data.highlightedID); } else if (data.action === "refresh") { enforceLocked = data.enforceLocked; renderWithZonesManager(rwzmSelectedId, data.highlightedID); } else if (data.action === "removeZoneOnAllEntities") { enforceLocked = data.enforceLocked; rwzmRemoveZoneFromAllEntities(data.zoneID, data.enforceLocked, data.highlightedID); } else if (data.action === "replaceZoneOnAllEntities") { enforceLocked = data.enforceLocked; rwzmReplaceZoneOnAllEntities(data.targetZoneID, data.replacementZoneID, data.enforceLocked, data.highlightedID); } else if (data.action === "undo") { enforceLocked = data.enforceLocked; rwzmUndoLastAction(data.highlightedID); } }