-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvolts.min.js
1 lines (1 loc) · 39.2 KB
/
volts.min.js
1
import Scene from"Scene";import Diagnostics from"Diagnostics";import Reactive from"Reactive";import Time from"Time";import Blocks from"Blocks";import CameraInfo from"CameraInfo";import Materials from"Materials";let Persistence,Multipeer;const _plugins={};export const plugins=Object.defineProperties({},{oimo:{get:()=>safeImportPlugins("oimo")}});function safeImportPlugins(name,version){if(!_plugins[name]){const fileName=`${name}.plugin.js`;try{if("oimo"!==name)throw new Error("Plugin name is undefined");_plugins.oimo=require("./oimo.plugin"),version&&version!==_plugins[name].VERSION&&report(`Plugin versions for "${name}" do not match. Expected version: ${version}, but received "${_plugins[name].VERSION}". Please make sure you include a compatible version of "${name}" in your project.`).asIssue("error"),_plugins[name].onImport&&!_plugins[name].onImport()&&report(`Plugin "${name} onImport function failed. Please check with the Plugin's creator"`)}catch(error){report(`Could not find module "${name}". Please make sure you include the "${fileName}" file in your project.\n${error}`).asIssue("error")}}return _plugins[name]}const PI=3.14159265359,TWO_PI=6.28318530718;function getUUIDv4(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(c){const r=16*Math.random()|0;return("x"==c?r:3&r|8).toString(16)}))}const pAll=async(queue,concurrency,areFn)=>{let index=0;const results=[],execThread=async()=>{for(;index<queue.length;){const curIndex=index++;results[curIndex]=await(areFn?queue[curIndex]():queue[curIndex])}},threads=[];for(let thread=0;thread<concurrency;thread++)threads.push(execThread());return await Promise.all(threads),results},promiseAllConcurrent=(n,areFn)=>list=>pAll(list,n,areFn),prettifyJSON=(obj,spacing=2)=>JSON.stringify(obj,null,spacing);export const report=function(...msg){let message;return message=msg.length>1?msg.join("\n"):msg[0],{asIssue:(lvl="warn")=>{message=new Error(`${message}`),message=`Message: ${message.message?message.message:message}\n\nInfo: This issue arose during execution.\nIf you believe it's related to VOLTS itself, please report it as a Github issue here: https://github.com/tomaspietravallo/sparkar-volts/issues\nPlease make your report detailed (include this message too!), and if possible, include a package of your current project\n\nStack: ${message.stack?message.stack:void 0}`,((lvl,msg)=>{if("throw"===lvl)throw msg;Diagnostics[lvl]?Diagnostics[lvl](msg):Diagnostics.warn(msg+`\n\n[[logger not found: ${lvl}]]`)})(lvl,message)},asBackwardsCompatibleDiagnosticsError:()=>{Diagnostics.error?Diagnostics.error(message):Diagnostics.warn?Diagnostics.warn(message):Diagnostics.log(message)}}};report.getSceneInfo=async function({getMaterials:getMaterials,getTextures:getTextures,getIdentifiers:getIdentifiers,getPositions:getPositions}={getMaterials:!0,getTextures:!0,getIdentifiers:!0,getPositions:!0}){const Instance=World.getInstance(!1),info={};if(Instance&&Instance.loaded){const sceneData={},keys=Object.keys(Instance.assets);for(let index=0;index<keys.length;index++){const key=keys[index],element=Instance.assets[key],getElementData=async e=>{if(!e)return{warning:"no-element-was-found"};const data={};let mat,tex;return data.name=e.name,data.hidden=e.hidden.pinLastValue(),getIdentifiers&&(data.identifier=e.identifier),getPositions&&(data.position=Vector.fromSignal(e.transform.position).toString(5)),(getMaterials||getTextures)&&(mat=e.getMaterial&&await e.getMaterial()||{},getMaterials&&(data.material=mat.name||"undefined"),getMaterials&&getIdentifiers&&(data["material-id"]=mat.identifier||"undefined")),getTextures&&(tex=mat&&mat.getDiffuse&&await mat.getDiffuse()||{},data.texture=tex.name||"undefined",getIdentifiers&&(data["texture-id"]=tex.identifier||"undefined")),data};Array.isArray(element)&&element.length>1?sceneData[key]=await promiseAllConcurrent(10,!0)(element.map((e=>getElementData.bind(this,e)))):sceneData[key]=element?await getElementData(element[0]):`obj[key] is possibly undefined. key: ${key}`}info.scene=sceneData}else info.scene="no instance was found, or the current instance has not loaded yet";return info.modules={Persistence:!!Persistence,Multipeer:!!Multipeer,dynamicInstancing:!!Scene.create,writableSignals:!!Reactive.scalarSignalSource},prettifyJSON(info)};export function transformAcrossSpaces(vec,vecParentSpace,targetParentSpace){if(!(vec&&vec.z&&vec.pinLastValue))throw new Error("@ transformAcrossSpaces: Argument vec is not defined, or is not a VectorSignal");if(!(vecParentSpace&&vecParentSpace.inverse&&vecParentSpace.pinLastValue))throw new Error("@ transformAcrossSpaces: Argument vecParentSpace is not defined, or is not a TransformSignal");if(!(targetParentSpace&&targetParentSpace.inverse&&targetParentSpace.pinLastValue))throw new Error("@ transformAcrossSpaces: Argument targetParentSpace is not defined, or is not a TransformSignal");return targetParentSpace.inverse().applyToPoint(vecParentSpace.applyToPoint(vec))}export const randomBetween=(min,max)=>Math.random()*(max-min)+min;export function hsv2rgb(h,s,v){h*=360;const f=(n,k=(n+h/60)%6)=>v-v*s*Math.max(Math.min(k,4-k,1),0);return[f(5),f(3),f(1)]}export function allBinaryOptions(len,a,b){const binary=[];for(let index=0;index<2**len;index++){const binaryString=index.toString(2);binary.push((Array(len-binaryString.length).fill("0").join("")+binaryString).split("").map((n=>Number(n)?a:b)))}return binary}export var PRODUCTION_MODES;!function(PRODUCTION_MODES){PRODUCTION_MODES.PRODUCTION="PRODUCTION",PRODUCTION_MODES.DEV="DEV",PRODUCTION_MODES.NO_AUTO="NO_AUTO"}(PRODUCTION_MODES||(PRODUCTION_MODES={}));class VoltsWorld{constructor(){this.mode=VoltsWorld.userConfig.mode,this.assets={},this.internalData={initPromise:this.init.bind(this,VoltsWorld.userConfig.assets,VoltsWorld.userConfig.loadStates),running:!1,loaded:!1,events:{},elapsedTime:0,frameCount:0,timedEvents:[],userFriendlySnapshot:{},formattedValuesToSnapshot:{},FLAGS:{stopTimeout:!1,lockInternalSnapshotOverride:!1},quaternions:new Map,Camera:null},this.internalData.formattedValuesToSnapshot=this.signalsToSnapshot_able(VoltsWorld.userConfig.snapshot),Object.defineProperty(this,"rawInitPromise",{value:this.internalData.initPromise(),enumerable:!1,writable:!1,configurable:!1});for(let index=0;index<VoltsWorld.subscriptions.length;index++)VoltsWorld.subscriptions[index]()}static getInstance(config){if(!1===config)return VoltsWorld.instance;if(VoltsWorld.instance)config&&Diagnostics.warn("@ VoltsWorld.getInstance: 'config' was provided (attempted to create new instance) but there's already an instance running");else{if("object"!=typeof config||null===config)throw new Error("@ VoltsWorld.getInstance: 'config' was not provided, but is required when creating the first instance");if(!config.mode)throw new Error("@ VoltsWorld.getInstance: 'config.mode' was not provided, but is required when creating the first instance");if(!Object.values(PRODUCTION_MODES).includes(config.mode)&&-1===config.mode.indexOf("x"))throw new Error(`@ VoltsWorld.getInstance: 'config.mode' was provided, but was not valid.\n\nAvailable modes are: ${Object.values(PRODUCTION_MODES)}`);config.loadStates=config.loadStates||[],Array.isArray(config.loadStates),config.loadStates,config.assets=config.assets||{},config.snapshot=config.snapshot||{},VoltsWorld.userConfig=config,VoltsWorld.instance=new VoltsWorld}return VoltsWorld.instance}static subscribeToInstance(cb){return"function"==typeof cb&&!!VoltsWorld.subscriptions.push(cb)}static devClear(){VoltsWorld.userConfig=void 0,VoltsWorld.instance=void 0,VoltsWorld.subscriptions=[]}async init(assets,states){this.internalData.Camera=await Scene.root.findFirst("Camera"),this.internalData.FLAGS.lockInternalSnapshotOverride||this.addToSnapshot({__volts__internal__focalDistance:this.internalData.Camera.focalPlane.distance,__volts__internal__time:Time.ms,__volts__internal__screen:Scene.unprojectToFocalPlane(Reactive.point2d(0,0)),__volts__internal__screenSizePixels:CameraInfo.previewSize}),this.internalData.FLAGS.lockInternalSnapshotOverride=!0,await promiseAllConcurrent(10,!0)(states.map((s=>s.loadState)));const keys=Object.keys(assets),getAssets=await promiseAllConcurrent(10,!1)(keys.map((n=>assets[n])));for(let k=0;k<keys.length;k++){if(!getAssets[k])throw new Error(`@ Volts.World.init: Object(s) not found. Key: "${keys[k]}"`);this.assets[keys[k]]=Array.isArray(getAssets[k])?getAssets[k].sort(((a,b)=>a.name.localeCompare(b.name))):getAssets[k]}this.internalData.loaded=!0,this.mode!==PRODUCTION_MODES.NO_AUTO&&this.run()}run(){if(this.internalData.running)return!1;this.internalData.FLAGS.stopTimeout=!1,this.internalData.running=!0;const lastThreeFrames=[];let offset=0;const loop=()=>{Time.setTimeoutWithSnapshot(this.internalData.formattedValuesToSnapshot,((_,snapshot)=>{snapshot=this.formattedSnapshotToUserFriendly(snapshot),this.internalData.userFriendlySnapshot={...this.internalData.userFriendlySnapshot,...snapshot},lastThreeFrames[0]||(offset=this.internalData.userFriendlySnapshot.__volts__internal__time||0);const delta=(this.internalData.userFriendlySnapshot.__volts__internal__time||0)-offset-this.internalData.elapsedTime,fps=Math.round(1e3/delta*10)/10;if(this.internalData.elapsedTime+=delta,lastThreeFrames.length>2?(lastThreeFrames[0]=lastThreeFrames[1],lastThreeFrames[1]=lastThreeFrames[2],lastThreeFrames[2]=this.internalData.userFriendlySnapshot.__volts__internal__time):lastThreeFrames.push(this.internalData.userFriendlySnapshot.__volts__internal__time),lastThreeFrames[0]===lastThreeFrames[1]&&lastThreeFrames[1]===lastThreeFrames[2]&&VoltsWorld.userConfig.mode!==PRODUCTION_MODES.PRODUCTION)return loop();const run=()=>{const onFramePerformanceData={fps:fps,delta:delta,frameCount:this.internalData.frameCount};if(this.runTimedEvents(onFramePerformanceData),this.emitEvent("frameUpdate",this.internalData.userFriendlySnapshot,onFramePerformanceData),this.internalData.frameCount+=1,!this.internalData.FLAGS.stopTimeout)return loop()};if(0===this.frameCount){let loadReturn;VoltsWorld.userConfig.mode!==PRODUCTION_MODES.NO_AUTO&&(delete this.internalData.formattedValuesToSnapshot.__volts__internal__screen,delete this.internalData.formattedValuesToSnapshot.__volts__internal__screenSizePixels,delete this.internalData.formattedValuesToSnapshot.__volts__internal__focalDistance,-1!==this.mode.indexOf("x")&&(this.mode=this.internalData.userFriendlySnapshot.__volts__internal__screenSizePixels.equals(new Vector(this.mode.split("x").map((n=>Number(n)))))?"DEV":"PRODUCTION"),this.emitEvent("load",this.internalData.userFriendlySnapshot)),loadReturn&&loadReturn.then?loadReturn.then(run):run()}else run()}),0)};return loop(),!0}get loaded(){return this.internalData.loaded}get running(){return this.internalData.running}get frameCount(){return this.internalData.frameCount}get snapshot(){return this.internalData.userFriendlySnapshot}forceAssetReload(){return this.internalData.initPromise()}stop({clearTimedEvents:clearTimedEvents}={clearTimedEvents:!1}){return!!this.internalData.running&&(this.internalData.running=!1,clearTimedEvents&&(this.internalData.timedEvents=[]),this.internalData.FLAGS.stopTimeout=!0,!0)}emitEvent(event,...args){const shouldBind=["load","frameUpdate","internal"].some((e=>e===event)),evts=this.internalData.events[event]||[];for(let index=0;index<evts.length;index++){const event=evts[index];shouldBind?event.bind(this)(...args):event(...args)}}onEvent(event,cb){return(this.internalData.events[event]=this.internalData.events[event]||[]).push(cb),()=>this.internalData.events[event]=(this.internalData.events[event]||[]).filter((i=>i!==cb))}onNextTick(cb){return this.setTimedEvent(cb,{ms:0,recurring:!1,onNext:this.frameCount})}setTimeout(cb,ms){return this.setTimedEvent(cb,{ms:ms,recurring:!1})}setInterval(cb,ms){return this.setTimedEvent(cb,{ms:ms,recurring:!0})}setDebounce(cb,ms,trailing=!1){let timer;return trailing?(...args)=>{timer&&timer.clear(),timer=this.setTimeout((()=>{cb.apply(this,args)}),ms)}:(...args)=>{timer||cb.apply(this,args),timer&&timer.clear(),timer=this.setTimeout((()=>{timer=void 0}),ms)}}setTimedEvent(cb,{ms:ms,recurring:recurring,onNext:onNext}){const event={created:this.internalData.elapsedTime,lastCall:this.internalData.elapsedTime,count:0,delay:ms,recurring:recurring,cb:cb,onNext:onNext};return this.internalData.timedEvents.push(event),{clear:()=>this.internalData.timedEvents=(this.internalData.timedEvents||[]).filter((i=>i!==event))}}runTimedEvents(onFramePerformanceData){this.internalData.timedEvents=this.internalData.timedEvents.sort(((e1,e2)=>e1.lastCall+e1.delay-(e2.lastCall+e2.delay)));let i=this.internalData.timedEvents.length;for(;i--;){const event=this.internalData.timedEvents[i];(void 0!==event.onNext&&event.onNext!==this.frameCount||void 0===event.onNext&&event.lastCall+event.delay<this.internalData.elapsedTime)&&(event.cb.apply(this,[this.internalData.elapsedTime-event.created,event.count,event.lastCall,event.created,onFramePerformanceData]),this.internalData.timedEvents[i].count++,event.recurring?this.internalData.timedEvents[i].lastCall=this.internalData.elapsedTime:this.internalData.timedEvents.splice(i,1))}}signalsToSnapshot_able(values){const suffix=getUUIDv4(),getKey=(k,e)=>`CONVERTED::${k}::${e}::${suffix}`,tmp={},keys=Object.keys(values);for(let i=0;i<keys.length;i++){const key=keys[i],signal=values[key];if(!signal)throw new Error(`@ (static) signalsToSnapshot_able: value[key] is not defined. Key: "${key}"`);if(signal.w)tmp[getKey(key,"w4")]=signal.w,tmp[getKey(key,"z4")]=signal.z,tmp[getKey(key,"y4")]=signal.y,tmp[getKey(key,"x4")]=signal.x,signal.eulerAngles&&this.internalData.quaternions.set(key,!0);else if(signal.z)tmp[getKey(key,"z3")]=signal.z,tmp[getKey(key,"y3")]=signal.y,tmp[getKey(key,"x3")]=signal.x;else if(signal.y)tmp[getKey(key,"y2")]=signal.y,tmp[getKey(key,"x2")]=signal.x;else{if(!(signal.xor||signal.concat||signal.pinLastValue))throw new Error(`@ (static) signalsToSnapshot_able: The provided Signal is not defined or is not supported. Key: "${key}"\n\nPlease consider opening an issue/PR: https://github.com/tomaspietravallo/sparkar-volts/issues`);tmp[getKey(key,"x1")]=signal}}return tmp}formattedSnapshotToUserFriendly(snapshot){let keys=Object.keys(snapshot);const signals={};for(let i=0;i<keys.length;i++){const key=keys[i],parts=key.split("::");if(4!==parts.length||"CONVERTED"!==parts[0])throw new Error(`@ Volts.World.formattedSnapshotToUserFriendly: Signal is missing the correct prefix, or is missing parts. Key: ${key}. Parts: ${parts}`);const name=parts[1],[component,dimension]=parts[2].split(""),uuid=parts[3];signals[name]=[Number(dimension),uuid]}keys=Object.keys(signals);const result={};for(let i=0;i<keys.length;i++){const name=keys[i],[dim,uuid]=signals[name];(!Number.isFinite(dim)||0==dim||dim>4)&&report(`@ Volts.World.formattedSnapshotToUserFriendly: dimension of signals[name] not 1|2|3|4. Dim: ${dim}. Name: ${name}.\n\nKeys: ${keys}`).asIssue("throw");const arr=[];for(let index=0;index<dim;index++)arr.push(snapshot[`CONVERTED::${name}::${Vector.components[index]}${dim}::${uuid}`]);this.internalData.quaternions.has(name)?result[name]=new Quaternion(arr[3],arr[0],arr[1],arr[2]):result[name]=dim>=2?new Vector(arr):arr[0]}return result}addToSnapshot(obj={}){if(this.internalData.FLAGS.lockInternalSnapshotOverride&&!Object.keys(obj).every((k=>-1===k.indexOf("__volts__internal"))))throw new Error("Cannot override internal key after the internal snapshot override has been locked");this.internalData.formattedValuesToSnapshot=Object.assign(this.internalData.formattedValuesToSnapshot,this.signalsToSnapshot_able(obj))}removeFromSnapshot(keys){const keysToRemove=Array.isArray(keys)?keys:[keys];if(this.internalData.FLAGS.lockInternalSnapshotOverride&&!keysToRemove.every((k=>-1===k.indexOf("__volts__internal"))))throw new Error("Cannot remove internal key after the internal snapshot override has been locked");const matches=Object.keys(this.internalData.formattedValuesToSnapshot).filter((k=>-1!==keysToRemove.indexOf(k.split("::")[1])));for(let index=0;index<matches.length;index++){const match=matches[index];delete this.internalData.formattedValuesToSnapshot[match]}}getWorldSpaceScreenBounds(){if(!this.internalData.running)throw new Error("Vector.getWorldSpaceScreenBounds can only be called when there's a Volts.World instance running");return this.internalData.userFriendlySnapshot.__volts__internal__screen.copy().abs().mul(1,-1,0)}}VoltsWorld.subscriptions=[];export const Vector=function(...args){if(args[0]instanceof Vector)return args[0].copy();Array.isArray(args[0])?this.values=args[0]:1===args.length?this.values=[args[0],args[0],args[0]]:null==args[0]?this.values=[0,0,0]:this.values=args;let e=0===this.values.length;for(let i=0;i<this.values.length;i++)e=e||"number"!=typeof this.values[i];if(e)throw new Error(`@ Vector.constructor: Values provided are not valid. args: ${args}. this.values: ${this.values}`);return this.dimension=this.values.length,this};Object.defineProperties(Vector.prototype,{x:{get:function(){return this.values[0]},set:function(x){this.values[0]=x}},y:{get:function(){if(this.dimension<2)throw new Error("Cannot get Vector.y, vector is a scalar");return this.values[1]},set:function(y){if(this.dimension<2)throw new Error("Cannot get Vector.y, vector is a scalar");this.values[1]=y}},z:{get:function(){if(this.dimension<3)throw new Error("Cannot get Vector.z, vector is not 3D");return this.values[2]},set:function(z){if(this.dimension<3)throw new Error("Cannot get Vector.z, vector is not 3D");this.values[2]=z}},w:{get:function(){if(this.dimension<4)throw new Error("Cannot get Vector.w, vector is not 4D");return this.values[3]},set:function(w){if(this.dimension<4)throw new Error("Cannot get Vector.w, vector is not 4D");this.values[3]=w}},signal:{get:function(){if(this.rs)return this.rs;const uuid=getUUIDv4(),vals=this.values;for(let index=0;index<this.dimension;index++){const c=Vector.components[index];this[`r${c}`]=Reactive.scalarSignalSource(`v${this.dimension}-${c}-${uuid}`),this[`r${c}`].set(vals[index])}if(1===this.dimension)this.rs=this.rx.signal;else if(2===this.dimension)this.rs=Reactive.point2d(this.rx.signal,this.ry.signal);else if(3===this.dimension)this.rs=Reactive.vector(this.rx.signal,this.ry.signal,this.rz.signal);else{if(4!==this.dimension)throw new Error("Tried to get the Signal of a N>4 Vector instance. Signals are only available for Vectors with up to 4 dimensions");this.rs=Reactive.pack4(this.rx.signal,this.ry.signal,this.rz.signal,this.rw.signal)}return this.rs}},pointSignal:{get:function(){if(this.rps)return this.rps;if(3!==this.dimension)throw new Error("@Vector.pointSignal accessor only available on 3D Vectors. Please use Vector.signal instead");const uuid=getUUIDv4(),vals=this.values;for(let index=0;index<3;index++){const c=Vector.components[index];this[`r${c}`]=Reactive.scalarSignalSource(`v${this.dimension}-${c}-${uuid}`),this[`r${c}`].set(vals[index])}return this.rps=Reactive.point(this.rx.signal,this.ry.signal,this.rz.signal),this.rps}}}),Vector.convertToSameDimVector=function(dim,...args){if(!args)throw new Error("@ Vector.convertToSameDimVector: No values provided");if(1==args.length){if(args[0]instanceof Vector){if(args[0].dimension==dim)return args[0];if(args[0].dimension>dim)return new Vector(args[0].values.slice(0,dim));throw new Error(`@ Vector.convertToVector: values provided are not valid. Dimensions do not match. dim: ${dim}. args(s): ${args}`)}if(Array.isArray(args[0])){if(args[0].length==dim)return new Vector(args[0]);if(args[0].length>dim)return new Vector(args[0].slice(0,dim));throw new Error(`@ Vector.convertToVector: values provided are not valid. Dimensions do not match. dim: ${dim}. args(s): ${args}`)}if("number"==typeof args[0])return new Vector(new Array(dim).fill(args[0]));throw new Error(`@ Vector.convertToVector: values provided are not valid. dim: ${dim}. args(s): ${args}`)}if(!Array.isArray(args)||!args.every((a=>"number"==typeof a))||args.length<dim)throw new Error(`@ Vector.convertToVector: values provided are not valid. dim: ${dim}. args(s): ${args}`);return new Vector(args.splice(0,dim))},Vector.screenToWorld=function(x,y,focalPlane=!0){const Instance=VoltsWorld.getInstance(!1);if(!Instance||!Instance.running)throw new Error("Vector.screenToWorld can only be called when there's a Volts.World instance running");if("number"!=typeof x||"number"!=typeof y)throw new Error(`@ Vector.screenToWorld: values provided are not valid. Values: x: ${x}, y: ${y}`);x=2*(x-.5),y=2*(y-.5);const bounds=Instance.getWorldSpaceScreenBounds();return new Vector(bounds.values[0]*x,bounds.values[1]*y,focalPlane?Instance.snapshot.__volts__internal__focalDistance:0)},Vector.fromSignal=function(s){if(!s)throw new Error("@ Volts.Vector.fromSignal: s is not defined");const tmp=[];if(!s.x)return new Vector([s.pinLastValue()]);for(let index=0;index<Vector.components.length;index++){const e=s[Vector.components[index]];e&&tmp.push(e.pinLastValue())}return new Vector(tmp)},Vector.random2D=function(magnitude=1){const angle=Math.random();return new Vector(Math.cos(angle)*magnitude,Math.sin(angle)*magnitude)},Vector.random3D=function(magnitude=1){const angle=Math.random()*TWO_PI,vz=2*Math.random()-1,vzBase=Math.sqrt(1-vz*vz),vx=vzBase*Math.cos(angle),vy=vzBase*Math.sin(angle);return new Vector(vx*magnitude,vy*magnitude,vz*magnitude)},Vector.components=["x","y","z","w"],Vector.prototype.add=function(...args){const b=Vector.convertToSameDimVector(this.dimension,...args).values;return this.values=this.values.map(((v,i)=>v+b[i])),this},Vector.prototype.sub=function(...args){const b=Vector.convertToSameDimVector(this.dimension,...args).values;return this.values=this.values.map(((v,i)=>v-b[i])),this},Vector.prototype.mul=function(...args){const b=Vector.convertToSameDimVector(this.dimension,...args).values;return this.values=this.values.map(((v,i)=>v*b[i])),this},Vector.prototype.div=function(...args){const b=Vector.convertToSameDimVector(this.dimension,...args).values;if(![...this.values,...b].every((v=>"number"==typeof v&&Number.isFinite(v)))||!b.every((v=>0!==v)))throw new Error(`@ Vector.div: values provided are not valid. this value(s): ${this.values}\n\nb value(s): ${b}`);return this.values=this.values.map(((v,i)=>v/b[i])),this},Vector.prototype.dot=function(...args){const b=Vector.convertToSameDimVector(this.dimension,...args).values;return this.values.map(((x,i)=>this.values[i]*b[i])).reduce(((acc,val)=>acc+val))},Vector.prototype.distance=function(...other){return Vector.convertToSameDimVector(this.dimension,...other).copy().sub(this).mag()},Vector.prototype.magSq=function(){return this.values.reduce(((acc,val)=>acc+val*val))},Vector.prototype.mag=function(){return this.values.map((v=>v*v)).reduce(((acc,val)=>acc+val))**.5},Vector.prototype.setMag=function(newMag){return this.normalize().mul(newMag)},Vector.prototype.abs=function(){return this.values=this.values.map((v=>v<0?-v:v)),this},Vector.prototype.normalize=function(){const len=this.mag();return 0!==len&&this.mul(1/len),this},Vector.prototype.copy=function(){return new Vector([...this.values])},Vector.prototype.equals=function(b){return!!b&&this.dimension===b.dimension&&this.values.every(((v,i)=>v===b.values[i]))},Vector.prototype.toString=function(toFixed=5){return`Vector<${this.dimension}>${this.rs?" (WRS)":""} [${(toFixed?this.values.map((v=>v.toFixed(toFixed))):this.values).toString()}]`},Vector.prototype.toArray=function(){return[...this.values]},Vector.prototype.setSignalComponents=function(){this.rx&&this.rx.set(this.values[0]),this.ry&&this.ry.set(this.values[1]),this.rz&&this.rz.set(this.values[2]),this.rw&&this.rw.set(this.values[3])},Vector.prototype.disposeSignalResources=function(){this.rx&&this.rx.dispose(),this.ry&&this.ry.dispose(),this.rz&&this.rz.dispose(),this.rw&&this.rw.dispose()},Vector.prototype.cross=function(...args){if(3!==this.dimension)throw`Attempting to use Vector<3>.cross on non 3D vector. Dim: ${this.dimension}`;const b=Vector.convertToSameDimVector(3,...args);return new Vector(this.values[1]*b.values[2]-this.values[2]*b.values[1],this.values[2]*b.values[0]-this.values[0]*b.values[2],this.values[0]*b.values[1]-this.values[1]*b.values[0])},Vector.prototype.applyQuaternion=function(q){q=q.normalized;const x=this.x,y=this.y,z=this.z,qx=q.x,qy=q.y,qz=q.z,qw=q.w,ix=qw*x+qy*z-qz*y,iy=qw*y+qz*x-qx*z,iz=qw*z+qx*y-qy*x,iw=-qx*x-qy*y-qz*z;return this.values=[ix*qw+iw*-qx+iy*-qz-iz*-qy,iy*qw+iw*-qy+iz*-qx-ix*-qz,iz*qw+iw*-qz+ix*-qy-iy*-qx],this},Vector.prototype.heading=function(){return Math.atan2(this.values[1],this.values[0])},Vector.prototype.rotate=function(a){const newHeading=Math.atan2(this.values[1],this.values[0])+a,mag=this.mag();return this.values[0]=Math.cos(newHeading)*mag,this.values[1]=Math.sin(newHeading)*mag,this};export class Quaternion{constructor(...args){if(args&&void 0!==args[0]?args[0]instanceof Quaternion?this.values=args[0].values:Array.isArray(args[0])?this.values=args[0]:this.values=args:this.values=[1,0,0,0],!this.values.every((v=>"number"==typeof v&&Number.isFinite(v)))||4!==this.values.length)throw new Error(`@ Quaternion.constructor: Values provided are not valid. args: ${args}. this.values: ${this.values}`)}static convertToQuaternion(...args){let tmp=[];if(tmp=args[0]instanceof Quaternion?args[0].values:Array.isArray(args[0])?args[0]:args,!tmp.every((v=>"number"==typeof v&&Number.isFinite(v)))||4!==tmp.length)throw new Error(`@ Quaternion.constructor: Values provided are not valid. args: ${args}. tmp: ${tmp}`);return new Quaternion(tmp)}static identity(){return new Quaternion(1,0,0,0)}static fromEuler(...args){const euler=Vector.convertToSameDimVector(3,...args),yaw=euler.values[2],pitch=euler.values[1],roll=euler.values[0],cy=Math.cos(.5*yaw),sy=Math.sin(.5*yaw),cp=Math.cos(.5*pitch),sp=Math.sin(.5*pitch),cr=Math.cos(.5*roll),sr=Math.sin(.5*roll);return new Quaternion(cr*cp*cy+sr*sp*sy,sr*cp*cy-cr*sp*sy,cr*sp*cy+sr*cp*sy,cr*cp*sy-sr*sp*cy)}static createFromAxisAngle(axis,angle){const halfAngle=.5*angle,s=Math.sin(halfAngle),q=new Quaternion;return q.values[1]=axis.values[0]*s,q.values[2]=axis.values[1]*s,q.values[3]=axis.values[2]*s,q.values[0]=Math.cos(halfAngle),q}static lookAt(sourcePoint,destPoint){const forwardVector=destPoint.copy().sub(sourcePoint).normalize(),dot=new Vector(0,0,1).dot(forwardVector);if(Math.abs(dot+1)<1e-6)return new Quaternion(0,1,0,PI);if(Math.abs(dot-1)<1e-6)return new Quaternion([1,0,0,0]);const rotAngle=Math.acos(dot),rotAxis=new Vector([0,0,1]).cross(forwardVector).normalize();return Quaternion.createFromAxisAngle(rotAxis,rotAngle)}static lookAtOptimized(headingVector3DArray){const forwardVector=[...headingVector3DArray];let mag=Math.sqrt(forwardVector[0]**2+forwardVector[1]**2+forwardVector[2]**2);0!==mag&&(forwardVector[0]/=mag),0!==mag&&(forwardVector[1]/=mag),0!==mag&&(forwardVector[2]/=mag);const dot=forwardVector[2];if(Math.abs(dot+1)<1e-5)return new Quaternion(0,1,0,PI);if(Math.abs(dot-1)<1e-5)return new Quaternion(1,0,0,0);let rotAngle=Math.acos(dot);const rotAxis=[-forwardVector[1],forwardVector[0],0];mag=(rotAxis[0]**2+rotAxis[1]**2)**.5,0!==mag&&(rotAxis[0]/=mag),0!==mag&&(rotAxis[1]/=mag),rotAngle*=.5;const s=Math.sin(rotAngle);return new Quaternion(Math.cos(rotAngle),rotAxis[0]*s,rotAxis[1]*s,rotAxis[2]*s)}static slerp(q1,q2,t){const q=new Quaternion,cosHalfTheta=q1.w*q2.w+q1.x*q2.x+q1.y*q2.y+q1.z*q2.z;if(Math.abs(cosHalfTheta)>=1)return q.w=q1.w,q.x=q1.x,q.y=q1.y,q.z=q1.z,q;const halfTheta=Math.acos(cosHalfTheta),sinHalfTheta=(1-cosHalfTheta*cosHalfTheta)**.5;if(Math.abs(sinHalfTheta)<.001)return q.w=.5*q1.w+.5*q2.w,q.x=.5*q1.x+.5*q2.x,q.y=.5*q1.y+.5*q2.y,q.z=.5*q1.z+.5*q2.z,q;const ra=Math.sin((1-t)*halfTheta)/sinHalfTheta,rb=Math.sin(t*halfTheta)/sinHalfTheta;return q.w=q1.w*ra+q2.w*rb,q.x=q1.x*ra+q2.x*rb,q.y=q1.y*ra+q2.y*rb,q.z=q1.z*ra+q2.z*rb,q}toQuaternionSignal(){return Reactive.quaternion(this.values[0],this.values[1],this.values[2],this.values[3])}calcNorm(){return(this.values[0]**2+this.values[1]**2+this.values[2]**2+this.values[3]**2)**.5}normalize(){const norm=this.calcNorm();return this.values[0]/=norm,this.values[1]/=norm,this.values[2]/=norm,this.values[3]/=norm,this}add(...other){const b=Quaternion.convertToQuaternion(...other).values;return this.values[0]=this.values[0]+b[0],this.values[1]=this.values[1]+b[1],this.values[2]=this.values[2]+b[2],this.values[3]=this.values[3]+b[3],this}mul(...other){const b=Quaternion.convertToQuaternion(...other),w1=this.w,x1=this.x,y1=this.y,z1=this.z,w2=b.w,x2=b.x,y2=b.y,z2=b.z;return this.w=w1*w2-x1*x2-y1*y2-z1*z2,this.x=w1*x2+x1*w2+y1*z2-z1*y2,this.y=w1*y2+y1*w2+z1*x2-x1*z2,this.z=w1*z2+z1*w2+x1*y2-y1*x2,this}copy(){return new Quaternion([...this.values])}setSignalComponents(){this.rw&&this.rw.set(this.values[0]),this.rx&&this.rx.set(this.values[1]),this.ry&&this.ry.set(this.values[2]),this.rz&&this.rz.set(this.values[3])}disposeSignalResources(){this.rw&&this.rw.dispose(),this.rx&&this.rx.dispose(),this.ry&&this.ry.dispose(),this.rz&&this.rz.dispose()}toEulerArray(){const angles=[],sinr_cosp=2*(this.w*this.x+this.y*this.z),cosr_cosp=1-2*(this.x*this.x+this.y*this.y);angles[0]=Math.atan2(sinr_cosp,cosr_cosp);const sinp=2*(this.w*this.y-this.z*this.x);Math.abs(sinp)>=1?angles[1]=PI/2*Math.sign(sinp):angles[1]=Math.asin(sinp);const siny_cosp=2*(this.w*this.z+this.x*this.y),cosy_cosp=1-2*(this.y*this.y+this.z*this.z);return angles[2]=Math.atan2(siny_cosp,cosy_cosp),angles}toString(toFixed=5){return`Quaternion${this.rs?" (WRS)":""}: [${this.values.map((v=>v.toFixed(toFixed)))}]`}toArray(){return[...this.values]}get normalized(){return new Quaternion([...this.values]).normalize()}get w(){return this.values[0]}set w(w){this.values[0]=w}get x(){return this.values[1]}set x(x){this.values[1]=x}get y(){return this.values[2]}set y(y){this.values[2]=y}get z(){return this.values[3]}set z(z){this.values[3]=z}get signal(){if(this.rs)return this.rs;const uuid=getUUIDv4(),vals=this.values;for(let index=0;index<4;index++){const c=Quaternion.components[index];this[`r${c}`]=Reactive.scalarSignalSource(`quat-${c}-${uuid}`),this[`r${c}`].set(vals[index])}return this.rs=Reactive.quaternion(this.rw.signal,this.rx.signal,this.ry.signal,this.rz.signal),this.rs}}Quaternion.components=["w","x","y","z"];export class State{constructor(persistenceKey){if(!persistenceKey)throw new Error("@ Volts.State: argument 'persistenceKey' is not defined");this.key=persistenceKey;try{Persistence||(Persistence=require("Persistence"))}catch{throw new Error('@ Volts.State: Persistence is not enabled as a capability, or is not available in the current target platforms.\n\nTo use Volts.State, please go to your project capabilities, inspect the target platforms, and remove the ones that don\'t support "Persistence"')}this._data={},Object.defineProperty(this,"loadState",{value:async()=>{const loadedDataFromPersistence=await Promise.race([Persistence.userScope.get(this.key).catch((()=>new Error(`@ Volts.State: The key provided: "${this.key}" is not whitelisted.\n\ngo to Project > Capabilities > Persistence > then write the key into the field (case sensitive). If there are multiple keys, separate them with spaces`))),new Promise((resolve=>{Time.setTimeout(resolve,350)}))]);if(loadedDataFromPersistence instanceof Error)throw loadedDataFromPersistence;if(loadedDataFromPersistence&&loadedDataFromPersistence.data){this._data=JSON.parse(loadedDataFromPersistence.data);const keys=Object.keys(this._data);for(let index=0;index<keys.length;index++){const key=keys[index];this._data[key].dimension&&Array.isArray(this._data[key].values)&&(this._data[key]=new Vector(this._data[key].values))}}this.loaded=!0},enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(this,"rawConstructorPromise",{value:this.loadState(),enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(this,"wipe",{value:()=>{this._data={}},enumerable:!1,writable:!1,configurable:!1})}setPersistenceAPI(){Persistence.userScope.set(this.key,{data:JSON.stringify(this._data)})}setValue(key,value){this.data[key]=value instanceof Vector||value instanceof Quaternion?value.copy():value,this.setPersistenceAPI()}get data(){return this._data}}export var SceneObjectClassNames;!function(SceneObjectClassNames){SceneObjectClassNames.Plane="Plane",SceneObjectClassNames.Canvas="Canvas",SceneObjectClassNames.PlanarImage="PlanarImage",SceneObjectClassNames.AmbientLightSource="AmbientLightSource",SceneObjectClassNames.DirectionalLightSource="DirectionalLightSource",SceneObjectClassNames.PointLightSource="PointLightSource",SceneObjectClassNames.SpotLightSource="SpotLightSource",SceneObjectClassNames.ParticleSystem="ParticleSystem",SceneObjectClassNames.SceneObject="SceneObject"}(SceneObjectClassNames||(SceneObjectClassNames={}));export var MaterialClassNames;!function(MaterialClassNames){MaterialClassNames.DefaultMaterial="DefaultMaterial",MaterialClassNames.BlendedMaterial="BlendedMaterial",MaterialClassNames.PhysicallyBasedMaterial="PhysicallyBasedMaterial",MaterialClassNames.FacePaintMaterial="FacePaintMaterial"}(MaterialClassNames||(MaterialClassNames={}));export class Object3D{constructor(body){if(this.pos=new Vector,this.rot=new Quaternion,this.acc=new Vector,this.vel=new Vector,this.scl=new Vector(1,1,1),this.box=new Vector(.05),this.awake=!0,this.body=body,null!==body){const p=new Promise((resolve=>{(body?Promise.resolve(body):Scene.create("Plane")).then((async plane=>{!body&&await Scene.root.addChild(plane),plane.transform.position=this.pos.signal,plane.transform.rotation=this.rot.signal,plane.transform.scale=this.scl.signal,resolve(plane)}))}));null==body&&(this.body=p)}}lookAtOther(other){return this.rot.values=Quaternion.lookAt(this.pos,other.pos).values,this}lookAtHeading(){return this.rot.values=Quaternion.lookAtOptimized(this.vel.values).values,this}update({pos:pos,rot:rot}={}){pos&&this.pos.setSignalComponents(),rot&&this.rot.setSignalComponents()}setPos(...newPos){return this.pos.values=Vector.convertToSameDimVector(3,...newPos).values,this}setRot(...newRot){return this.rot.values=Quaternion.convertToQuaternion(...newRot).values,this}setScl(...newScl){return this.scl.values=Vector.convertToSameDimVector(3,...newScl).values,this}bindMesh(sceneObjectBase){return sceneObjectBase.transform.position=this.pos.signal,sceneObjectBase.transform.rotation=this.rot.signal,this}static async createDebugMaterial(hue){return void 0===hue&&(hue=0),Materials.create(MaterialClassNames.DefaultMaterial,{opacity:1,blendMode:"ALPHA",doubleSided:!0}).then((m=>(m.setTextureSlot("DIFFUSE",Reactive.pack4(...hsv2rgb(hue,1,1),1)),m)))}setMaterial(material){return this.body.then?this.body.then((b=>b.material=material)):this.body.material=material,this}}export class Pool{constructor(objectsOrPath,root,initialState={}){if(!Blocks.instantiate)throw new Error("@ VOLTS.Pool.constructor: Dynamic instances capability is not enabled.\n\nPlease go to Project > Properties > Capabilities > + Scripting Dynamic Instantiation");if(!objectsOrPath)throw new Error("@ VOLTS.Pool.constructor: objectsOrPath is undefined");this.seed=Array.isArray(objectsOrPath)?objectsOrPath:[objectsOrPath],this.objects=[],this.initialState=initialState,root&&(this.root=this.setRoot(root))}async instantiate(){const assetName=this.seed[Math.floor(Math.random()*this.seed.length)],i=await(Object.values(SceneObjectClassNames).includes(assetName)?Scene.create(assetName,this.initialState):Blocks.instantiate(assetName,this.initialState));if(this.root=(this.root||{}).then?await this.root.catch((()=>{})):this.root,!this.root||!this.root.addChild)throw new Error("@ VOLTS.Pool.instantiate: No root was provided, or the string provided did not match a valid SceneObject");await this.root.addChild(i),this.objects.push(new Object3D(i))}async getObject(){let obj=this.objects.pop();return obj||(await this.instantiate(),obj=this.objects.pop()),obj.returnToPool=()=>this.objects.push(obj),obj}async populate(amount,limitConcurrentPromises){await promiseAllConcurrent(limitConcurrentPromises||10,!0)(new Array(amount).fill(this.instantiate.bind(this)))}async setRoot(newRoot){if(this.root="string"==typeof newRoot?await Scene.root.findFirst(newRoot).catch((()=>{})):newRoot,!this.root)throw new Error(`Error @ VOLTS.Pool.setRoot: Scene.root.findFirst was unable to find the provided root: "${newRoot}"`);return this.root}get hasPreInstancedObjectsAvailable(){return this.objects.length>0}get preInstancedObjectsCount(){return this.objects.length}}Pool.SceneObjects=SceneObjectClassNames;export class Cube{constructor(origin,size){if(!(origin&&origin.values&&Number.isFinite(origin.values[0])&&"number"==typeof size))throw new Error(`@ Volts.Cube.constructor: Values provided are not valid. origin: ${origin}, size: ${origin}`);this.x=origin.x,this.y=origin.y,this.z=origin.z,this.s=size}contains(Object3D){return Object3D.pos.x>=this.x-this.s&&Object3D.pos.x<this.x+this.s&&Object3D.pos.y>=this.y-this.s&&Object3D.pos.y<this.y+this.s&&Object3D.pos.z>=this.z-this.s&&Object3D.pos.z<this.z+this.s}debugVisualize(hue){const origin=new Vector(this.x,this.y,this.z);return hue=hue||Math.random(),Object3D.createDebugMaterial(hue).then((mat=>{allBinaryOptions(3,-this.s,this.s).forEach((o=>new Object3D(void 0).setPos(origin.copy().add(o)).setScl(.1).setMaterial(mat)))}))}toString(){return`x: ${this.x.toFixed(5)} y: ${this.y.toFixed(5)} z: ${this.z.toFixed(5)} s: ${this.s.toFixed(5)}`}}export class Tree{constructor(boundary,capacity,level){if(!(boundary.contains&&"number"==typeof capacity&&"number"==typeof level&&level<=5))throw new Error(`@ Volts.Tree.constructor: Values provided are not valid. boundary: ${boundary}, capacity: ${capacity}, level: ${level}`);this.boundary=boundary,this.capacity=capacity,this.level=level,this.points=[],this.divided=!1}subdivide(){this.divided=!0;const cubePos=new Vector(this.boundary.x,this.boundary.y,this.boundary.z),tmp=this.points;this.points=allBinaryOptions(3,-this.boundary.s/2,this.boundary.s/2).map((o=>new Tree(new Cube(cubePos.copy().add(o),this.boundary.s/2),this.capacity,this.level+1)));for(let index=0;index<tmp.length;index++)this.insert(tmp[index])}insert(Object3D){if(!this.boundary.contains(Object3D))return 0===this.level&&Diagnostics.warn(`Out of bounds contains on level 0. Tree.boundary: ${this.boundary.toString()}. Point: ${Object3D.pos.toString()}`),!1;if(this.divided){for(let index=0;index<8;index++)if(this.points[index].insert(Object3D))return!0}else{if(!this.divided&&this.points.length<this.capacity)return this.points.push(Object3D),!0;if(!this.divided)return this.subdivide(),this.insert(Object3D)}}allSharingSubTree(other,includeSelf){const stack=[this];for(;0!==stack.length;){const e=stack.pop();if(e.boundary&&e.boundary.contains(other)){if(!e.divided)return e.points.filter((e=>!!includeSelf||e!==other));stack.push(...e.points)}}return[]}getTotalObjectCount(){let total=0;const stack=[this];for(;0!==stack.length;){const e=stack.pop();e.points&&e.divided?stack.push(...e.points):total+=e.points.length}return total}forceSubdivideAndColorAround(object,downToLevel=5){const stack=[this],cubes=[];let hue=-.1;for(;0!==stack.length;){const e=stack.pop();if(e.boundary&&e.boundary.contains(object))if(e.divided)cubes.push(e),stack.push(...e.points);else{if(!(e.level<downToLevel))break;e.subdivide(),cubes.push(e),stack.push(...e.points)}}cubes.forEach((c=>c.debugVisualize(hue+=.1)))}debugVisualize(hue){const stack=[this];for(;0!==stack.length;){const e=stack.pop();e.boundary&&e.divided&&(stack.push(...e.points),e.boundary.debugVisualize())}}}export const privates={clearVoltsWorld:VoltsWorld.devClear,report:report,promiseAllConcurrent:promiseAllConcurrent};export const World={getInstance:VoltsWorld.getInstance,subscribeToInstance:VoltsWorld.subscribeToInstance};export default{World:World,Vector:Vector,Quaternion:Quaternion,State:State,Object3D:Object3D,Pool:Pool,Cube:Cube,Tree:Tree,PRODUCTION_MODES:PRODUCTION_MODES,plugins:plugins};!Reactive.scalarSignalSource&&report("Please enable Writeable Signal Sources in the project capabilities for Volts to work properly").asBackwardsCompatibleDiagnosticsError();