multyx-client 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,57 @@
1
+ import { RawObject } from "./types";
2
+ export declare class Controller {
3
+ private mouseGetter;
4
+ listening: Set<string>;
5
+ ws: WebSocket;
6
+ preventDefault: boolean;
7
+ keys: RawObject<boolean>;
8
+ mouse: {
9
+ x: number;
10
+ y: number;
11
+ down: boolean;
12
+ centerX: number;
13
+ centerY: number;
14
+ scaleX: number;
15
+ scaleY: number;
16
+ };
17
+ constructor(ws: WebSocket);
18
+ /**
19
+ * Map the canvas to specified top left and bottom right positions
20
+ * @param canvas HTML canvas element
21
+ * @param canvasContext 2D rendering context for canvas
22
+ * @param top Canvas position to correspond to top of canvas
23
+ * @param left Canvas position to correspond to left of canvas
24
+ * @param bottom Canvas position to correspond to bottom of canvas
25
+ * @param right Canvas position to correspond to right of canvas
26
+ * @param anchor Anchor the origin at a specific spot on the canvas
27
+ */
28
+ mapCanvasPosition(canvas: HTMLCanvasElement, position: {
29
+ top?: number;
30
+ bottom?: number;
31
+ left?: number;
32
+ right?: number;
33
+ anchor?: 'center' | 'left' | 'right' | 'top' | 'bottom' | 'topleft' | 'topright' | 'bottomleft' | 'bottomright';
34
+ }): void;
35
+ /**
36
+ * @param centerX Anchor x-value corresponding to mouse position x-value of 0
37
+ * @param centerY Anchor y-value corresponding to mouse position y-value of 0
38
+ * @param anchor HTML Element to read mouse position relative to
39
+ * @param scaleX Number of anchor pixels corresponding to a mouse position x-value change of 1
40
+ * @param scaleY Number of anchor pixels corresponding to a mouse position y-value change of 1
41
+ */
42
+ mapMousePosition(centerX: number, centerY: number, anchor?: HTMLElement, scaleX?: number, scaleY?: number): void;
43
+ /**
44
+ * Map mouse position to the corresponding canvas coordinates on screen
45
+ * @param canvas Canvas element in DOM
46
+ */
47
+ mapMouseToCanvas(canvas: HTMLCanvasElement): void;
48
+ /**
49
+ * Utilize mouse coordinates of another object
50
+ * @param mouseGetter Callback that returns the mouse coordinates at any given time
51
+ */
52
+ setMouseAs(mouseGetter: () => {
53
+ x: number;
54
+ y: number;
55
+ }): void;
56
+ private relayInput;
57
+ }
@@ -0,0 +1,49 @@
1
+ import { Add } from './utils';
2
+ import { RawObject } from "./types";
3
+ import { Controller } from "./controller";
4
+ import { MultyxClientObject } from "./items";
5
+ import { Options } from "./options";
6
+ export default class Multyx {
7
+ ws: WebSocket;
8
+ uuid: string;
9
+ joinTime: number;
10
+ ping: number;
11
+ events: Map<string | Symbol, ((data?: any) => void)[]>;
12
+ self: RawObject;
13
+ all: RawObject;
14
+ clients: RawObject;
15
+ teams: RawObject;
16
+ controller: Controller;
17
+ options: Options;
18
+ private listenerQueue;
19
+ static Start: symbol;
20
+ static Connection: symbol;
21
+ static Disconnect: symbol;
22
+ static Edit: symbol;
23
+ static Native: symbol;
24
+ static Custom: symbol;
25
+ static Any: symbol;
26
+ constructor(options?: Options, callback?: () => void);
27
+ on(name: string | Symbol, callback: (data: RawObject) => void): void;
28
+ send(name: string, data: any, expectResponse?: boolean): Promise<unknown>;
29
+ /**
30
+ * Loop over a function
31
+ * @param callback Function to call on a loop
32
+ * @param timesPerSecond Recommended to leave blank. Number of times to loop in each second, if undefined, use requestAnimationFrame
33
+ */
34
+ loop(callback: () => void, timesPerSecond?: number): void;
35
+ /**
36
+ * Create a callback function that gets called for any current or future client
37
+ * @param callbackfn Function to call for every client
38
+ */
39
+ forAll(callback: (client: MultyxClientObject) => void): void;
40
+ private parseNativeEvent;
41
+ private initialize;
42
+ private parseEdit;
43
+ private parseSelf;
44
+ /**
45
+ * Add function to listener queue
46
+ * @param fn Function to call once frame is complete
47
+ */
48
+ [Add](fn: ((...args: any[]) => void)): void;
49
+ }
@@ -0,0 +1,5 @@
1
+ import MultyxClientList from "./list";
2
+ import MultyxClientObject from "./object";
3
+ import MultyxClientValue from "./value";
4
+ type MultyxClientItem<T = any> = T extends any[] ? MultyxClientList : T extends object ? MultyxClientObject : MultyxClientValue;
5
+ export { MultyxClientList, MultyxClientObject, MultyxClientValue, MultyxClientItem, };
@@ -0,0 +1,40 @@
1
+ import Multyx from '../';
2
+ import { MultyxClientItem } from '.';
3
+ import { EditWrapper } from '../utils';
4
+ import MultyxClientObject from "./object";
5
+ export default class MultyxClientList extends MultyxClientObject {
6
+ length: number;
7
+ get value(): any[];
8
+ constructor(multyx: Multyx, list: any[] | EditWrapper<any[]>, propertyPath: string[], editable: boolean);
9
+ set(index: string | number, value: any): boolean;
10
+ delete(index: string | number, native?: boolean): boolean;
11
+ /**
12
+ * Create a callback function that gets called for any current or future element in list
13
+ * @param callbackfn Function to call for every element
14
+ */
15
+ forAll(callbackfn: (value: any, index: number) => void): void;
16
+ push(...items: any): number;
17
+ pop(): MultyxClientItem | null;
18
+ unshift(...items: any[]): number;
19
+ shift(): import("./value").default | MultyxClientObject;
20
+ splice(start: number, deleteCount?: number, ...items: any[]): void;
21
+ filter(predicate: (value: any, index: number, array: MultyxClientList) => boolean): void;
22
+ map(callbackfn: (value: any, index: number, array: MultyxClientList) => any): void;
23
+ flat(): void;
24
+ reduce(callbackfn: (accumulator: any, currentValue: any, index: number, array: MultyxClientList) => any, startingAccumulator: any): any;
25
+ reduceRight(callbackfn: (accumulator: any, currentValue: any, index: number, array: MultyxClientList) => any, startingAccumulator: any): any;
26
+ reverse(): this;
27
+ forEach(callbackfn: (value: any, index: number, array: MultyxClientList) => void): void;
28
+ every(predicate: (value: any, index: number, array: MultyxClientList) => boolean): boolean;
29
+ some(predicate: (value: any, index: number, array: MultyxClientList) => boolean): boolean;
30
+ find(predicate: (value: any, index: number, array: MultyxClientList) => boolean): import("./value").default | MultyxClientObject;
31
+ findIndex(predicate: (value: any, index: number, array: MultyxClientList) => boolean): number;
32
+ deorder(): MultyxClientItem[];
33
+ deorderEntries(): [number, MultyxClientItem][];
34
+ entries(): [any, number][];
35
+ keys(): number[];
36
+ [Symbol.iterator](): Iterator<MultyxClientItem>;
37
+ toString: () => string;
38
+ valueOf: () => any[];
39
+ [Symbol.toPrimitive]: () => any[];
40
+ }
@@ -0,0 +1,30 @@
1
+ import { RawObject } from '../types';
2
+ import { EditWrapper, Unpack } from "../utils";
3
+ import type Multyx from '../index';
4
+ import type { MultyxClientItem } from ".";
5
+ export default class MultyxClientObject {
6
+ protected object: RawObject<MultyxClientItem>;
7
+ private multyx;
8
+ propertyPath: string[];
9
+ editable: boolean;
10
+ private setterListeners;
11
+ get value(): {};
12
+ constructor(multyx: Multyx, object: RawObject | EditWrapper<RawObject>, propertyPath: string[], editable: boolean);
13
+ has(property: any): boolean;
14
+ get(property: any): MultyxClientItem;
15
+ set(property: any, value: any): boolean;
16
+ delete(property: any, native?: boolean): boolean;
17
+ /**
18
+ * Create a callback function that gets called for any current or future property in object
19
+ * @param callbackfn Function to call for every property
20
+ */
21
+ forAll(callbackfn: (key: any, value: any) => void): void;
22
+ keys(): any[];
23
+ values(): any[];
24
+ entries(): [any, any][];
25
+ /**
26
+ * Unpack constraints from server
27
+ * @param constraints Packed constraints object mirroring MultyxClientObject shape
28
+ */
29
+ [Unpack](constraints: RawObject): void;
30
+ }
@@ -0,0 +1 @@
1
+ export default function MultyxClientItemRouter(data: any): any;
@@ -0,0 +1,31 @@
1
+ import type Multyx from '../';
2
+ import { Constraint, RawObject, Value } from "../types";
3
+ import { EditWrapper, Unpack } from '../utils';
4
+ export default class MultyxClientValue {
5
+ private _value;
6
+ private multyx;
7
+ propertyPath: string[];
8
+ editable: boolean;
9
+ constraints: {
10
+ [key: string]: Constraint;
11
+ };
12
+ private interpolator;
13
+ get value(): Value;
14
+ set value(v: Value);
15
+ constructor(multyx: Multyx, value: Value | EditWrapper<Value>, propertyPath: string[], editable: boolean);
16
+ set(value: Value | EditWrapper<Value>): boolean;
17
+ /**
18
+ * Unpack constraints sent from server and store
19
+ * @param constraints Packed constraints from server
20
+ */
21
+ [Unpack](constraints: RawObject): void;
22
+ /**
23
+ * Linearly interpolate value across frames
24
+ * Will run 1 frame behind on average
25
+ */
26
+ Lerp(): void;
27
+ PredictiveLerp(): void;
28
+ toString: () => string;
29
+ valueOf: () => Value;
30
+ [Symbol.toPrimitive]: () => Value;
31
+ }
@@ -0,0 +1,12 @@
1
+ import { Update } from "./types";
2
+ export declare class Message {
3
+ name: string;
4
+ data: any;
5
+ time: number;
6
+ native: boolean;
7
+ private constructor();
8
+ static BundleOperations(deltaTime: any, operations: any): string;
9
+ static Native(update: Update): string;
10
+ static Parse(str: string): Message;
11
+ static Create(name: string, data: any): string;
12
+ }
@@ -0,0 +1,8 @@
1
+ export type Options = {
2
+ port?: number;
3
+ secure?: boolean;
4
+ uri?: string;
5
+ verbose?: boolean;
6
+ logUpdateFrame?: boolean;
7
+ };
8
+ export declare const DefaultOptions: Options;
package/dist/options.js CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DefaultOptions = void 0;
4
4
  exports.DefaultOptions = {
5
- port: 443,
5
+ port: 8443,
6
6
  secure: false,
7
7
  uri: 'localhost',
8
8
  verbose: false,
@@ -0,0 +1,16 @@
1
+ export type RawObject<V = any> = {
2
+ [key: string | number | symbol]: V;
3
+ };
4
+ export type Value = string | number | boolean;
5
+ export type Constraint = (n: Value) => Value | null;
6
+ export type EditUpdate = {
7
+ instruction: 'edit';
8
+ path: string[];
9
+ value: any;
10
+ };
11
+ export type InputUpdate = {
12
+ instruction: 'input';
13
+ input: string;
14
+ data?: RawObject<Value>;
15
+ };
16
+ export type Update = EditUpdate | InputUpdate;
@@ -0,0 +1,28 @@
1
+ import { Constraint, RawObject, Value } from "./types";
2
+ export declare const Unpack: unique symbol;
3
+ export declare const Done: unique symbol;
4
+ export declare const Add: unique symbol;
5
+ export declare class EditWrapper<T> {
6
+ value: T;
7
+ constructor(value: T);
8
+ }
9
+ /**
10
+ * Set a customized interpolation curve for values to follow
11
+ * @param values Slices to interpolate through. Time must be between 0 and 1, while progress is the percentage between the old value and new value at the respective time, where 0 represents old value and 1 represents new value
12
+ * @example
13
+ * ```js
14
+ * car.get('speed').interpolate([
15
+ * { time: 0, progress: 0 },
16
+ * { time: 0.2, progress: 0.6 },
17
+ * { time: 0.4, progress: 1.2 },
18
+ * { time: 0.6, progress: 1.4 },
19
+ * { time: 0.8, progress: 1.2 },
20
+ * { time: 1, progress: 1 }
21
+ * ]);
22
+ * ```
23
+ */
24
+ export declare function Interpolate(object: RawObject, property: string, interpolationCurve: {
25
+ time: number;
26
+ progress: number;
27
+ }[]): void;
28
+ export declare function BuildConstraint(name: string, args: Value[]): Constraint | void;
package/multyx.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Multyx=e():t.Multyx=e()}(self,(()=>(()=>{"use strict";var t={376:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Controller=void 0;const i=s(210);e.Controller=class{constructor(t){this.listening=new Set,this.ws=t,this.preventDefault=!1,this.keys={},this.mouse={x:NaN,y:NaN,down:!1,centerX:0,centerY:0,scaleX:1,scaleY:1},document.addEventListener("keydown",(t=>{this.preventDefault&&t.preventDefault;const e=t.key.toLowerCase();this.keys[e]&&this.listening.has("keyhold")&&this.relayInput("keyhold",{code:e}),this.keys[t.code]&&this.listening.has("keyhold")&&this.relayInput("keyhold",{code:t.code}),this.listening.has(e)&&!this.keys[e]&&this.relayInput("keydown",{code:t.key}),this.listening.has(t.code)&&!this.keys[t.code]&&this.relayInput("keydown",{code:t.code}),this.keys[e]=!0,this.keys[t.code]=!0})),document.addEventListener("keyup",(t=>{this.preventDefault&&t.preventDefault;const e=t.key.toLowerCase();delete this.keys[e],delete this.keys[t.code],this.listening.has(e)&&this.relayInput("keyup",{code:e}),this.listening.has(t.code)&&this.relayInput("keyup",{code:t.code})})),document.addEventListener("mousedown",(t=>{if(this.preventDefault&&t.preventDefault,this.mouseGetter){const t=this.mouseGetter();this.mouse.x=t.x,this.mouse.y=t.y}else this.mouse.x=(t.clientX-this.mouse.centerX)/this.mouse.scaleX,this.mouse.y=(t.clientY-this.mouse.centerY)/this.mouse.scaleY;this.mouse.down=!0,this.listening.has("mousedown")&&this.relayInput("mousedown",{x:this.mouse.x,y:this.mouse.y})})),document.addEventListener("mouseup",(t=>{if(this.preventDefault&&t.preventDefault,this.mouseGetter){const t=this.mouseGetter();this.mouse.x=t.x,this.mouse.y=t.y}else this.mouse.x=(t.clientX-this.mouse.centerX)/this.mouse.scaleX,this.mouse.y=(t.clientY-this.mouse.centerY)/this.mouse.scaleY;this.mouse.down=!1,this.listening.has("mouseup")&&this.relayInput("mouseup",{x:this.mouse.x,y:this.mouse.y})})),document.addEventListener("mousemove",(t=>{if(this.preventDefault&&t.preventDefault,this.mouseGetter){const t=this.mouseGetter();this.mouse.x=t.x,this.mouse.y=t.y}else this.mouse.x=(t.clientX-this.mouse.centerX)/this.mouse.scaleX,this.mouse.y=(t.clientY-this.mouse.centerY)/this.mouse.scaleY;this.listening.has("mousemove")&&this.relayInput("mousemove",{x:this.mouse.x,y:this.mouse.y})}))}mapCanvasPosition(t,e){var s,i,o,n,r,h,l,a,u,c,f,p,d,m,g,v;const b="top"in e,y="bottom"in e,w="left"in e,M="right"in e,x=e.anchor,j=t.getBoundingClientRect(),S=(t,...e)=>{const s=t?"Cannot include value for ":"Must include value for ",i=1==e.length?e[0]:e.slice(0,-1).join(", ")+(t?" and ":" or ")+e.slice(-1)[0],o=x?" if anchoring at "+x:" if not anchoring";console.error(s+i+o)},k=j.width/j.height,E=j.height/j.width;if((Number.isNaN(k)||Number.isNaN(E))&&console.error("Canvas element bounding box is flat, canvas must be present on the screen"),x){if("center"==x){if(b&&y&&e.top!==-e.bottom||w&&M&&e.left!==-e.right)return S(!0,"top","bottom","left","right");b?(e.left=w?e.left:M?-e.right:-Math.abs(k*e.top),e.right=w?-e.left:M?e.right:Math.abs(k*e.top),e.bottom=-e.top):y?(e.left=w?e.left:M?-e.right:-Math.abs(k*e.bottom),e.right=w?-e.left:M?e.right:Math.abs(k*e.bottom),e.top=-e.bottom):w?(e.top=b?e.top:y?-e.bottom:-Math.abs(E*e.left),e.bottom=b?-e.top:y?e.bottom:Math.abs(E*e.left),e.right=-e.left):M&&(e.top=b?e.top:y?-e.bottom:-Math.abs(E*e.right),e.bottom=b?-e.top:y?e.bottom:Math.abs(E*e.right),e.left=-e.right)}else if("bottom"==x){if(!w&&!M&&!b)return S(!1,"left","right","top");if(e.bottom)return S(!0,"bottom");e.bottom=0,w?(null!==(s=e.top)&&void 0!==s||(e.top=Math.abs(E*e.left*2)),null!==(i=e.right)&&void 0!==i||(e.right=-e.left)):M?(null!==(o=e.top)&&void 0!==o||(e.top=Math.abs(E*e.right*2)),null!==(n=e.left)&&void 0!==n||(e.left=-e.right)):(e.left=-Math.abs(k*e.top/2),e.right=-e.left)}else if("top"==x){if(!w&&!M&&!y)return S(!1,"left","right","bottom");if(e.top)return S(!0,"top");e.top=0,w?(null!==(r=e.bottom)&&void 0!==r||(e.bottom=Math.abs(E*e.left*2)),null!==(h=e.right)&&void 0!==h||(e.right=-e.left)):M?(null!==(l=e.bottom)&&void 0!==l||(e.bottom=Math.abs(E*e.right*2)),null!==(a=e.left)&&void 0!==a||(e.left=-e.right)):(e.left=-Math.abs(k*e.bottom/2),e.right=-e.left)}else if("left"==x){if(!b&&!y&&!M)return S(!1,"top","bottom","right");if(w)return S(!0,"left");e.left=0,b?(null!==(u=e.right)&&void 0!==u||(e.right=-Math.abs(k*e.top*2)),null!==(c=e.bottom)&&void 0!==c||(e.bottom=-e.top)):y?(null!==(f=e.right)&&void 0!==f||(e.right=Math.abs(k*e.bottom*2)),null!==(p=e.top)&&void 0!==p||(e.top=-e.bottom)):(e.top=-Math.abs(E*e.right/2),e.bottom=-e.top)}else if("right"==x){if(!b&&!y&&!w)return S(!1,"top","bottom","left");if(M)return S(!0,"right");e.right=0,b?(null!==(d=e.left)&&void 0!==d||(e.left=-Math.abs(k*e.top*2)),null!==(m=e.bottom)&&void 0!==m||(e.bottom=-e.top)):y?(null!==(g=e.left)&&void 0!==g||(e.left=Math.abs(k*e.bottom*2)),null!==(v=e.top)&&void 0!==v||(e.top=-e.bottom)):(e.top=-Math.abs(E*e.right/2),e.bottom=-e.top)}else if("topleft"==x){if(!M&&!y)return S(!1,"right","bottom");if(w||b)return S(!0,"left","top");e.left=e.top=0,M?e.bottom=Math.abs(E*e.right):e.right=Math.abs(k*e.bottom)}else if("topright"==x){if(!w&&!y)return S(!1,"left","bottom");if(M||b)return S(!0,"right","top");e.right=e.top=0,w?e.bottom=Math.abs(E*e.left):e.left=Math.abs(k*e.bottom)}else if("bottomleft"==x){if(!M&&!b)return S(!1,"right","top");if(y||w)return S(!0,"bottom","left");e.left=e.bottom=0,M?e.top=Math.abs(E*e.right):e.right=Math.abs(k*e.top)}else if("bottomright"==x){if(!b&&!w)return S(!1,"top","left");if(M||y)return S(!0,"bottom","right");e.right=e.bottom=0,w?e.top=Math.abs(E*e.left):e.left=Math.abs(k*e.top)}}else{if(!b&&!y)return S(!1,"top","bottom");if(y?b||(e.top=e.bottom-t.height):e.bottom=e.top+t.height,!w&&!M)return S(!1,"left","right");M?w||(e.left=e.right-t.width):e.right=e.left+t.width}const O=t.getContext("2d");O.setTransform(1,0,0,1,0,0),t.width=Math.floor(Math.abs(e.right-e.left)),t.height=Math.floor(Math.abs(e.bottom-e.top)),e.right<e.left&&O.scale(-1,1),e.top>e.bottom&&O.scale(1,-1),O.translate(-e.left,-e.top)}mapMousePosition(t,e,s=document.body,i=1,o=i){const n=window.innerWidth/(s instanceof HTMLCanvasElement?s.width:s.clientWidth),r=window.innerHeight/(s instanceof HTMLCanvasElement?s.height:s.clientHeight),h=s.getBoundingClientRect();this.mouse.centerX=h.left+t*n,this.mouse.centerY=h.top+e*r,this.mouse.scaleX=i*n,this.mouse.scaleY=o*r}mapMouseToCanvas(t){const e=t.getContext("2d").getTransform(),s=t.getBoundingClientRect(),i=s.width/t.width,o=s.height/t.height;this.mouse.centerX=s.left+e.e*i,this.mouse.centerY=s.top+e.f*o,this.mouse.scaleX=i*e.a,this.mouse.scaleY=o*e.d}setMouseAs(t){this.mouseGetter=t}relayInput(t,e){if(1!==this.ws.readyState)throw new Error("Websocket connection is "+(2==this.ws.readyState?"closing":"closed"));this.ws.send(i.Message.Native(Object.assign({instruction:"input",input:t},e?{data:e}:{})))}}},34:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.MultyxClientValue=e.MultyxClientObject=e.MultyxClientList=void 0;const i=s(70);e.MultyxClientList=i.default;const o=s(614);e.MultyxClientObject=o.default;const n=s(501);e.MultyxClientValue=n.default},70:(t,e,s)=>{var i;Object.defineProperty(e,"__esModule",{value:!0});const o=s(787),n=s(614);class r extends n.default{get value(){const t=[];for(let e=0;e<this.length;e++)t[e]=this.get(e).value;return t}constructor(t,e,s=[],n){return super(t,{},s,n),this.toString=()=>this.value.toString(),this.valueOf=()=>this.value,this[i]=()=>this.value,this.length=0,this.push(...e instanceof o.EditWrapper?e.value.map((t=>new o.EditWrapper(t))):e),new Proxy(this,{has:(t,e)=>e in t||t.has(e),get:(t,e)=>e in t?t[e]:t.get(e),set:(t,e,s)=>e in t?(t[e]=s,!0):t.set(e,s),deleteProperty:(t,e)=>t.delete(e,!1)})}set(t,e){if("string"==typeof t&&(t=parseInt(t)),void 0===e)return this.delete(t,!1);if(e instanceof o.EditWrapper&&void 0===e.value)return this.delete(t,!0);const s=super.set(t,e);return s&&t>=this.length&&(this.length=t+1),s}delete(t,e=!1){"string"==typeof t&&(t=parseInt(t));const s=super.delete(t,e);return s&&(this.length=this.reduce(((t,e,s)=>void 0!==e?s+1:t),0)),s}forAll(t){for(let e=0;e<this.length;e++)t(this.get(e),e);super.forAll(((e,s)=>t(s,e)))}push(...t){for(const e of t)this.set(this.length,e);return this.length}pop(){if(0===this.length)return null;const t=this.get(this.length);return this.delete(this.length),t}unshift(...t){for(let e=this.length-1;e>=0;e--)e>=t.length?this.set(e,this.get(e-t.length)):this.set(e,t[e]);return this.length}shift(){if(0==this.length)return;this.length--;const t=this.get(0);for(let t=0;t<this.length;t++)this.set(t,this.get(t+1));return t}splice(t,e,...s){void 0===e&&(e=this.length-t);let i=s.length-e;if(i>0)for(let s=this.length-1;s>=t+e;s--)this.set(s+i,this.get(s));else if(i<0){for(let s=t+e;s<this.length;s++)this.set(s+i,this.get(s));const s=this.length;for(let t=s+i;t<s;t++)this.set(t,void 0)}for(let e=t;e<s.length;e++)this.set(e,s[e])}filter(t){const e=[];for(let s=0;s<this.length;s++)e.push(t(this.get(s),s,this));let s=0;for(let t=0;t<e.length;t++)e[t]&&s&&this.set(t-s,this.get(t)),e[t]||s--}map(t){for(let e=0;e<this.length;e++)this.set(e,t(this.get(e),e,this))}flat(){for(let t=0;t<this.length;t++){const e=this.get(t);if(e instanceof r)for(let s=0;s<e.length;s++)t++,this.set(t,e[s])}}reduce(t,e){for(let s=0;s<this.length;s++)e=t(e,this.get(s),s,this);return e}reduceRight(t,e){for(let s=this.length-1;s>=0;s--)e=t(e,this.get(s),s,this);return e}reverse(){let t=this.length-1;for(let e=0;e<t;e++){const s=this.get(e),i=this.get(t);this.set(e,i),this.set(t,s)}return this}forEach(t){for(let e=0;e<this.length;e++)t(this.get(e),e,this)}every(t){for(let e=0;e<this.length;e++)if(!t(this.get(e),e,this))return!1;return!0}some(t){for(let e=0;e<this.length;e++)if(t(this.get(e),e,this))return!0;return!1}find(t){for(let e=0;e<this.length;e++)if(t(this.get(e),e,this))return this.get(e)}findIndex(t){for(let e=0;e<this.length;e++)if(t(this.get(e),e,this))return e;return-1}deorder(){const t=[];for(const e in this.object)t.push(this.get(e));return t}deorderEntries(){const t=[];for(const e in this.object)t.push([parseInt(e),this.get(e)]);return t}entries(){const t=[];for(let e=0;e<this.length;e++)t.push([this.get(e),e]);return t}keys(){return Array(this.length).fill(0).map(((t,e)=>e))}[Symbol.iterator](){const t=[];for(let e=0;e<this.length;e++)t[e]=this.get(e);return t[Symbol.iterator]()}}i=Symbol.toPrimitive,e.default=r},614:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0});const i=s(210),o=s(787),n=s(735),r=s(501);class h{get value(){const t={};for(const e in this.object)t[e]=this.object[e];return t}constructor(t,e,s=[],i){this.object={},this.propertyPath=s,this.multyx=t,this.editable=i,this.setterListeners=[],e instanceof h&&(e=e.value);for(const t in e instanceof o.EditWrapper?e.value:e)this.set(t,e instanceof o.EditWrapper?new o.EditWrapper(e.value[t]):e[t]);if(this.constructor===h)return new Proxy(this,{has:(t,e)=>t.has(e),get:(t,e)=>e in t?t[e]:t.get(e),set:(t,e,s)=>e in t?(t[e]=s,!0):t.set(e,s),deleteProperty:(t,e)=>t.delete(e,!1)})}has(t){return t in this.object}get(t){return this.object[t]}set(t,e){if(void 0===e)return this.delete(t);if(this.object[t]instanceof r.default)return this.object[t].set(e);if(e instanceof o.EditWrapper&&void 0===e.value)return this.delete(t,!0);if(!(e instanceof o.EditWrapper||this.editable))return this.multyx.options.verbose&&console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join(".")+"."+t}' to ${e}`),!1;this.object[t]=new((0,n.default)(e instanceof o.EditWrapper?e.value:e))(this.multyx,e,[...this.propertyPath,t],this.editable);for(const e of this.setterListeners)this.multyx[o.Add]((()=>{this.has(t)&&e(t,this.get(t))}));return e instanceof o.EditWrapper||this.multyx.ws.send(i.Message.Native({instruction:"edit",path:this.propertyPath,value:this.object[t].value})),!0}delete(t,e=!1){return this.editable||e?(delete this.object[t],e||this.multyx.ws.send(i.Message.Native({instruction:"edit",path:[...this.propertyPath,t],value:void 0})),!0):(this.multyx.options.verbose&&console.error(`Attempting to delete property that is not editable. Deleting '${this.propertyPath.join(".")+"."+t}'`),!1)}forAll(t){for(let e in this.object)t(e,this.get(e));this.setterListeners.push(t)}keys(){return Object.keys(this.object)}values(){return Object.values(this.object)}entries(){const t=[];for(let e in this.object)t.push([e,this.get(e)]);return t}[o.Unpack](t){for(const e in t)this.object[e][o.Unpack](t[e])}}e.default=h},735:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(t){return Array.isArray(t)?s(70).default:"object"==typeof t?s(614).default:s(501).default}},501:(t,e,s)=>{var i;Object.defineProperty(e,"__esModule",{value:!0});const o=s(210),n=s(787);class r{get value(){return this.interpolator?this.interpolator.get():this._value}set value(t){this._value=t,this.interpolator&&this.interpolator.set()}constructor(t,e,s=[],o){this.toString=()=>this.value.toString(),this.valueOf=()=>this.value,this[i]=()=>this.value,this.propertyPath=s,this.editable=o,this.multyx=t,this.constraints={},this.set(e)}set(t){if(t instanceof n.EditWrapper)return this.value=t.value,!0;if(!this.editable)return this.multyx.options.verbose&&console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join(".")}' to ${t}`),!1;let e=t;for(const s in this.constraints)if(e=(0,this.constraints[s])(e),null===e)return this.multyx.options.verbose&&console.error(`Attempting to set property that failed on constraint. Setting '${this.propertyPath.join(".")}' to ${t}, stopped by constraint '${s}'`),!1;return this.value===e?(this.value=e,!0):(this.value=e,this.multyx.ws.send(o.Message.Native({instruction:"edit",path:this.propertyPath,value:e})),!0)}[n.Unpack](t){for(const[e,s]of Object.entries(t)){const t=(0,n.BuildConstraint)(e,s);t&&(this.constraints[e]=t)}}Lerp(){this.interpolator={history:[{value:this._value,time:Date.now()},{value:this._value,time:Date.now()}],get:()=>{const[t,e]=this.interpolator.history,s=Math.min(1,(Date.now()-t.time)/Math.min(250,t.time-e.time));return Number.isNaN(s)||"number"!=typeof t.value||"number"!=typeof e.value?t.value:t.value*s+e.value*(1-s)},set:()=>{this.interpolator.history.pop(),this.interpolator.history.unshift({value:this._value,time:Date.now()})}}}PredictiveLerp(){this.interpolator={history:[{value:this._value,time:Date.now()},{value:this._value,time:Date.now()},{value:this._value,time:Date.now()}],get:()=>{const[t,e,s]=this.interpolator.history,i=Math.min(1,(Date.now()-t.time)/(t.time-e.time));return Number.isNaN(i)||"number"!=typeof s.value||"number"!=typeof t.value||"number"!=typeof e.value||Math.abs((t.value-e.value)/(e.value-s.value)-1)>.2?t.value:t.value*(1+i)-e.value*i},set:()=>{this.interpolator.history.pop(),this.interpolator.history.unshift({value:this._value,time:Date.now()})}}}}i=Symbol.toPrimitive,e.default=r},210:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Message=void 0;class s{constructor(t,e,s=!1){this.name=t,this.data=e,this.time=Date.now(),this.native=s}static BundleOperations(t,e){return Array.isArray(e)||(e=[e]),JSON.stringify(new s("_",{operations:e,deltaTime:t}))}static Native(t){return JSON.stringify(new s("_",t,!0))}static Parse(t){const e=JSON.parse(t);return"_"==e.name[0]&&(e.name=e.name.slice(1)),new s(e.name,e.data,""==e.name)}static Create(t,e){if(0==t.length)throw new Error("Multyx message cannot have empty name");if("_"==t[0]&&(t="_"+t),"function"==typeof e)throw new Error("Multyx data must be JSON storable");return JSON.stringify(new s(t,e))}}e.Message=s},944:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultOptions=void 0,e.DefaultOptions={port:443,secure:!1,uri:"localhost",verbose:!1,logUpdateFrame:!1}},787:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.EditWrapper=e.Add=e.Done=e.Unpack=void 0,e.Interpolate=function(t,e,s){let i={value:t[e],time:Date.now()},o={value:t[e],time:Date.now()};Object.defineProperty(t,e,{get:()=>{const t=o.time-i.time;let e=s[0],n=s[0];for(const i of s)t>i.time&&i.time>e.time&&(e=i),t<i.time&&i.time<n.time&&(n=i);const r=(t-e.time)/(n.time-e.time),h=e.progress+r*(n.progress-e.progress);return Number.isNaN(h)?i.value:o.value*h+i.value*(1-h)},set:t=>Date.now()-o.time<10?(o.value=t,!0):(i=Object.assign({},o),o={value:t,time:Date.now()},!0)})},e.BuildConstraint=function(t,e){return"min"==t?t=>t>=e[0]?t:e[0]:"max"==t?t=>t<=e[0]?t:e[0]:"int"==t?t=>Math.floor(t):"ban"==t?t=>e.includes(t)?null:t:"disabled"==t?t=>e[0]?null:t:t=>t},e.Unpack=Symbol("unpack"),e.Done=Symbol("done"),e.Add=Symbol("add"),e.EditWrapper=class{constructor(t){this.value=t}}}},e={};function s(i){var o=e[i];if(void 0!==o)return o.exports;var n=e[i]={exports:{}};return t[i](n,n.exports,s),n.exports}var i={};return(()=>{var t=i;const e=s(210),o=s(787),n=s(376),r=s(34),h=s(944);class l{constructor(t={},s){this.options=Object.assign(Object.assign({},h.DefaultOptions),t);const i=`ws${this.options.secure?"s":""}://${this.options.uri}:${this.options.port}/`;this.ws=new WebSocket(i),this.ping=0,this.events=new Map,this.self={},this.all={},this.teams={},this.clients={},this.controller=new n.Controller(this.ws),this.listenerQueue=[],null==s||s(),this.ws.onmessage=t=>{var s,i,o;const n=e.Message.Parse(t.data);this.ping=2*(Date.now()-n.time),n.native?(this.parseNativeEvent(n),null===(s=this.events.get(l.Native))||void 0===s||s.forEach((t=>t(n)))):n.name in this.events&&(this.events[n.name](n.data),null===(i=this.events.get(l.Custom))||void 0===i||i.forEach((t=>t(n)))),null===(o=this.events.get(l.Any))||void 0===o||o.forEach((t=>t(n)))}}on(t,e){var s;const i=null!==(s=this.events.get(t))&&void 0!==s?s:[];i.push(e),this.events.set(t,i)}send(t,s,i=!1){if("_"===t[0]&&(t="_"+t),this.ws.send(e.Message.Create(t,s)),i)return new Promise((e=>this.events.set(Symbol.for("_"+t),[e])))}loop(t,e){if(e)this.on(l.Start,(()=>setInterval(t,Math.round(1e3/e))));else{const e=()=>{t(),requestAnimationFrame(e)};this.on(l.Start,(()=>requestAnimationFrame(e)))}}forAll(t){this.on(l.Start,(()=>{this.teams.all.clients.forAll((e=>t(this.clients[e])))})),this.on(l.Connection,t)}parseNativeEvent(t){var e,s,i,o;this.options.logUpdateFrame&&console.log(t);for(const n of t.data)switch(n.instruction){case"init":this.initialize(n);for(const t of null!==(e=this.events.get(l.Start))&&void 0!==e?e:[])this.listenerQueue.push((()=>t(n)));this.events.has(l.Start)&&(this.events.get(l.Start).length=0);break;case"edit":this.parseEdit(n);for(const t of null!==(s=this.events.get(l.Edit))&&void 0!==s?s:[])this.listenerQueue.push((()=>t(n)));break;case"self":this.parseSelf(n);break;case"conn":this.clients[n.uuid]=new r.MultyxClientObject(this,n.data,[n.uuid],!1);for(const t of null!==(i=this.events.get(l.Connection))&&void 0!==i?i:[])this.listenerQueue.push((()=>t(this.clients[n.uuid])));break;case"dcon":for(const t of null!==(o=this.events.get(l.Disconnect))&&void 0!==o?o:[]){const e=this.clients[n.client].value;this.listenerQueue.push((()=>t(e)))}delete this.clients[n.client];break;case"resp":(0,this.events.get(Symbol.for("_"+n.name))[0])(n.response);break;default:this.options.verbose&&console.error("Server error: Unknown native Multyx instruction")}this.listenerQueue.forEach((t=>t())),this.listenerQueue.length=0}initialize(t){this.uuid=t.client.uuid,this.joinTime=t.client.joinTime,this.controller.listening=new Set(t.client.controller),this.teams=new r.MultyxClientObject(this,{},[],!0);for(const e of Object.keys(t.teams))this.teams[e]=new o.EditWrapper(t.teams[e]);this.all=this.teams.all,this.clients={};for(const[e,s]of Object.entries(t.clients))e!=this.uuid&&(this.clients[e]=new r.MultyxClientObject(this,new o.EditWrapper(s),[e],!1));const e=new r.MultyxClientObject(this,new o.EditWrapper(t.client.self),[this.uuid],!0);this.self=e,this.clients[this.uuid]=e;for(const[e,s]of Object.entries(t.constraintTable))(this.uuid==e?this.self:this.teams[e])[o.Unpack](s)}parseEdit(t){let e=t.team?this.teams:this.clients;if(e){for(const s of t.path.slice(0,-1))s in e||(e[s]=new o.EditWrapper({})),e=e[s];e[t.path.slice(-1)[0]]=new o.EditWrapper(t.value)}}parseSelf(t){if("controller"==t.prop)this.controller.listening=new Set(t.data);else if("uuid"==t.prop)this.uuid=t.data;else if("constraint"==t.prop){let e=this.uuid==t.data.path[0]?this.self:this.teams[t.data.path[0]];for(const s of t.data.path.slice(1))e=null==e?void 0:e[s];if(void 0===e)return;e[o.Unpack]({[t.data.name]:t.data.args})}}[o.Add](t){this.listenerQueue.push(t)}}l.Start=Symbol("start"),l.Connection=Symbol("connection"),l.Disconnect=Symbol("disconnect"),l.Edit=Symbol("edit"),l.Native=Symbol("native"),l.Custom=Symbol("custom"),l.Any=Symbol("any"),t.default=l})(),i.default})()));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Multyx=e():t.Multyx=e()}(self,(()=>(()=>{"use strict";var t={376:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Controller=void 0;const i=s(210);e.Controller=class{constructor(t){this.listening=new Set,this.ws=t,this.preventDefault=!1,this.keys={},this.mouse={x:NaN,y:NaN,down:!1,centerX:0,centerY:0,scaleX:1,scaleY:1},document.addEventListener("keydown",(t=>{this.preventDefault&&t.preventDefault;const e=t.key.toLowerCase();this.keys[e]&&this.listening.has("keyhold")&&this.relayInput("keyhold",{code:e}),this.keys[t.code]&&this.listening.has("keyhold")&&this.relayInput("keyhold",{code:t.code}),this.listening.has(e)&&!this.keys[e]&&this.relayInput("keydown",{code:t.key}),this.listening.has(t.code)&&!this.keys[t.code]&&this.relayInput("keydown",{code:t.code}),this.keys[e]=!0,this.keys[t.code]=!0})),document.addEventListener("keyup",(t=>{this.preventDefault&&t.preventDefault;const e=t.key.toLowerCase();delete this.keys[e],delete this.keys[t.code],this.listening.has(e)&&this.relayInput("keyup",{code:e}),this.listening.has(t.code)&&this.relayInput("keyup",{code:t.code})})),document.addEventListener("mousedown",(t=>{if(this.preventDefault&&t.preventDefault,this.mouseGetter){const t=this.mouseGetter();this.mouse.x=t.x,this.mouse.y=t.y}else this.mouse.x=(t.clientX-this.mouse.centerX)/this.mouse.scaleX,this.mouse.y=(t.clientY-this.mouse.centerY)/this.mouse.scaleY;this.mouse.down=!0,this.listening.has("mousedown")&&this.relayInput("mousedown",{x:this.mouse.x,y:this.mouse.y})})),document.addEventListener("mouseup",(t=>{if(this.preventDefault&&t.preventDefault,this.mouseGetter){const t=this.mouseGetter();this.mouse.x=t.x,this.mouse.y=t.y}else this.mouse.x=(t.clientX-this.mouse.centerX)/this.mouse.scaleX,this.mouse.y=(t.clientY-this.mouse.centerY)/this.mouse.scaleY;this.mouse.down=!1,this.listening.has("mouseup")&&this.relayInput("mouseup",{x:this.mouse.x,y:this.mouse.y})})),document.addEventListener("mousemove",(t=>{if(this.preventDefault&&t.preventDefault,this.mouseGetter){const t=this.mouseGetter();this.mouse.x=t.x,this.mouse.y=t.y}else this.mouse.x=(t.clientX-this.mouse.centerX)/this.mouse.scaleX,this.mouse.y=(t.clientY-this.mouse.centerY)/this.mouse.scaleY;this.listening.has("mousemove")&&this.relayInput("mousemove",{x:this.mouse.x,y:this.mouse.y})}))}mapCanvasPosition(t,e){var s,i,o,n,r,h,l,a,u,c,f,p,d,m,g,v;const b="top"in e,y="bottom"in e,w="left"in e,M="right"in e,x=e.anchor,j=t.getBoundingClientRect(),S=(t,...e)=>{const s=t?"Cannot include value for ":"Must include value for ",i=1==e.length?e[0]:e.slice(0,-1).join(", ")+(t?" and ":" or ")+e.slice(-1)[0],o=x?" if anchoring at "+x:" if not anchoring";console.error(s+i+o)},k=j.width/j.height,E=j.height/j.width;if((Number.isNaN(k)||Number.isNaN(E))&&console.error("Canvas element bounding box is flat, canvas must be present on the screen"),x){if("center"==x){if(b&&y&&e.top!==-e.bottom||w&&M&&e.left!==-e.right)return S(!0,"top","bottom","left","right");b?(e.left=w?e.left:M?-e.right:-Math.abs(k*e.top),e.right=w?-e.left:M?e.right:Math.abs(k*e.top),e.bottom=-e.top):y?(e.left=w?e.left:M?-e.right:-Math.abs(k*e.bottom),e.right=w?-e.left:M?e.right:Math.abs(k*e.bottom),e.top=-e.bottom):w?(e.top=b?e.top:y?-e.bottom:-Math.abs(E*e.left),e.bottom=b?-e.top:y?e.bottom:Math.abs(E*e.left),e.right=-e.left):M&&(e.top=b?e.top:y?-e.bottom:-Math.abs(E*e.right),e.bottom=b?-e.top:y?e.bottom:Math.abs(E*e.right),e.left=-e.right)}else if("bottom"==x){if(!w&&!M&&!b)return S(!1,"left","right","top");if(e.bottom)return S(!0,"bottom");e.bottom=0,w?(null!==(s=e.top)&&void 0!==s||(e.top=Math.abs(E*e.left*2)),null!==(i=e.right)&&void 0!==i||(e.right=-e.left)):M?(null!==(o=e.top)&&void 0!==o||(e.top=Math.abs(E*e.right*2)),null!==(n=e.left)&&void 0!==n||(e.left=-e.right)):(e.left=-Math.abs(k*e.top/2),e.right=-e.left)}else if("top"==x){if(!w&&!M&&!y)return S(!1,"left","right","bottom");if(e.top)return S(!0,"top");e.top=0,w?(null!==(r=e.bottom)&&void 0!==r||(e.bottom=Math.abs(E*e.left*2)),null!==(h=e.right)&&void 0!==h||(e.right=-e.left)):M?(null!==(l=e.bottom)&&void 0!==l||(e.bottom=Math.abs(E*e.right*2)),null!==(a=e.left)&&void 0!==a||(e.left=-e.right)):(e.left=-Math.abs(k*e.bottom/2),e.right=-e.left)}else if("left"==x){if(!b&&!y&&!M)return S(!1,"top","bottom","right");if(w)return S(!0,"left");e.left=0,b?(null!==(u=e.right)&&void 0!==u||(e.right=-Math.abs(k*e.top*2)),null!==(c=e.bottom)&&void 0!==c||(e.bottom=-e.top)):y?(null!==(f=e.right)&&void 0!==f||(e.right=Math.abs(k*e.bottom*2)),null!==(p=e.top)&&void 0!==p||(e.top=-e.bottom)):(e.top=-Math.abs(E*e.right/2),e.bottom=-e.top)}else if("right"==x){if(!b&&!y&&!w)return S(!1,"top","bottom","left");if(M)return S(!0,"right");e.right=0,b?(null!==(d=e.left)&&void 0!==d||(e.left=-Math.abs(k*e.top*2)),null!==(m=e.bottom)&&void 0!==m||(e.bottom=-e.top)):y?(null!==(g=e.left)&&void 0!==g||(e.left=Math.abs(k*e.bottom*2)),null!==(v=e.top)&&void 0!==v||(e.top=-e.bottom)):(e.top=-Math.abs(E*e.right/2),e.bottom=-e.top)}else if("topleft"==x){if(!M&&!y)return S(!1,"right","bottom");if(w||b)return S(!0,"left","top");e.left=e.top=0,M?e.bottom=Math.abs(E*e.right):e.right=Math.abs(k*e.bottom)}else if("topright"==x){if(!w&&!y)return S(!1,"left","bottom");if(M||b)return S(!0,"right","top");e.right=e.top=0,w?e.bottom=Math.abs(E*e.left):e.left=Math.abs(k*e.bottom)}else if("bottomleft"==x){if(!M&&!b)return S(!1,"right","top");if(y||w)return S(!0,"bottom","left");e.left=e.bottom=0,M?e.top=Math.abs(E*e.right):e.right=Math.abs(k*e.top)}else if("bottomright"==x){if(!b&&!w)return S(!1,"top","left");if(M||y)return S(!0,"bottom","right");e.right=e.bottom=0,w?e.top=Math.abs(E*e.left):e.left=Math.abs(k*e.top)}}else{if(!b&&!y)return S(!1,"top","bottom");if(y?b||(e.top=e.bottom-t.height):e.bottom=e.top+t.height,!w&&!M)return S(!1,"left","right");M?w||(e.left=e.right-t.width):e.right=e.left+t.width}const O=t.getContext("2d");O.setTransform(1,0,0,1,0,0),t.width=Math.floor(Math.abs(e.right-e.left)),t.height=Math.floor(Math.abs(e.bottom-e.top)),e.right<e.left&&O.scale(-1,1),e.top>e.bottom&&O.scale(1,-1),O.translate(-e.left,-e.top)}mapMousePosition(t,e,s=document.body,i=1,o=i){const n=window.innerWidth/(s instanceof HTMLCanvasElement?s.width:s.clientWidth),r=window.innerHeight/(s instanceof HTMLCanvasElement?s.height:s.clientHeight),h=s.getBoundingClientRect();this.mouse.centerX=h.left+t*n,this.mouse.centerY=h.top+e*r,this.mouse.scaleX=i*n,this.mouse.scaleY=o*r}mapMouseToCanvas(t){const e=t.getContext("2d").getTransform(),s=t.getBoundingClientRect(),i=s.width/t.width,o=s.height/t.height;this.mouse.centerX=s.left+e.e*i,this.mouse.centerY=s.top+e.f*o,this.mouse.scaleX=i*e.a,this.mouse.scaleY=o*e.d}setMouseAs(t){this.mouseGetter=t}relayInput(t,e){if(1!==this.ws.readyState)throw new Error("Websocket connection is "+(2==this.ws.readyState?"closing":"closed"));this.ws.send(i.Message.Native(Object.assign({instruction:"input",input:t},e?{data:e}:{})))}}},34:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.MultyxClientValue=e.MultyxClientObject=e.MultyxClientList=void 0;const i=s(70);e.MultyxClientList=i.default;const o=s(614);e.MultyxClientObject=o.default;const n=s(501);e.MultyxClientValue=n.default},70:(t,e,s)=>{var i;Object.defineProperty(e,"__esModule",{value:!0});const o=s(787),n=s(614);class r extends n.default{get value(){const t=[];for(let e=0;e<this.length;e++)t[e]=this.get(e).value;return t}constructor(t,e,s=[],n){return super(t,{},s,n),this.toString=()=>this.value.toString(),this.valueOf=()=>this.value,this[i]=()=>this.value,this.length=0,this.push(...e instanceof o.EditWrapper?e.value.map((t=>new o.EditWrapper(t))):e),new Proxy(this,{has:(t,e)=>e in t||t.has(e),get:(t,e)=>e in t?t[e]:t.get(e),set:(t,e,s)=>e in t?(t[e]=s,!0):t.set(e,s),deleteProperty:(t,e)=>t.delete(e,!1)})}set(t,e){if("string"==typeof t&&(t=parseInt(t)),void 0===e)return this.delete(t,!1);if(e instanceof o.EditWrapper&&void 0===e.value)return this.delete(t,!0);const s=super.set(t,e);return s&&t>=this.length&&(this.length=t+1),s}delete(t,e=!1){"string"==typeof t&&(t=parseInt(t));const s=super.delete(t,e);return s&&(this.length=this.reduce(((t,e,s)=>void 0!==e?s+1:t),0)),s}forAll(t){for(let e=0;e<this.length;e++)t(this.get(e),e);super.forAll(((e,s)=>t(s,e)))}push(...t){for(const e of t)this.set(this.length,e);return this.length}pop(){if(0===this.length)return null;const t=this.get(this.length);return this.delete(this.length),t}unshift(...t){for(let e=this.length-1;e>=0;e--)e>=t.length?this.set(e,this.get(e-t.length)):this.set(e,t[e]);return this.length}shift(){if(0==this.length)return;this.length--;const t=this.get(0);for(let t=0;t<this.length;t++)this.set(t,this.get(t+1));return t}splice(t,e,...s){void 0===e&&(e=this.length-t);let i=s.length-e;if(i>0)for(let s=this.length-1;s>=t+e;s--)this.set(s+i,this.get(s));else if(i<0){for(let s=t+e;s<this.length;s++)this.set(s+i,this.get(s));const s=this.length;for(let t=s+i;t<s;t++)this.set(t,void 0)}for(let e=t;e<s.length;e++)this.set(e,s[e])}filter(t){const e=[];for(let s=0;s<this.length;s++)e.push(t(this.get(s),s,this));let s=0;for(let t=0;t<e.length;t++)e[t]&&s&&this.set(t-s,this.get(t)),e[t]||s--}map(t){for(let e=0;e<this.length;e++)this.set(e,t(this.get(e),e,this))}flat(){for(let t=0;t<this.length;t++){const e=this.get(t);if(e instanceof r)for(let s=0;s<e.length;s++)t++,this.set(t,e[s])}}reduce(t,e){for(let s=0;s<this.length;s++)e=t(e,this.get(s),s,this);return e}reduceRight(t,e){for(let s=this.length-1;s>=0;s--)e=t(e,this.get(s),s,this);return e}reverse(){let t=this.length-1;for(let e=0;e<t;e++){const s=this.get(e),i=this.get(t);this.set(e,i),this.set(t,s)}return this}forEach(t){for(let e=0;e<this.length;e++)t(this.get(e),e,this)}every(t){for(let e=0;e<this.length;e++)if(!t(this.get(e),e,this))return!1;return!0}some(t){for(let e=0;e<this.length;e++)if(t(this.get(e),e,this))return!0;return!1}find(t){for(let e=0;e<this.length;e++)if(t(this.get(e),e,this))return this.get(e)}findIndex(t){for(let e=0;e<this.length;e++)if(t(this.get(e),e,this))return e;return-1}deorder(){const t=[];for(const e in this.object)t.push(this.get(e));return t}deorderEntries(){const t=[];for(const e in this.object)t.push([parseInt(e),this.get(e)]);return t}entries(){const t=[];for(let e=0;e<this.length;e++)t.push([this.get(e),e]);return t}keys(){return Array(this.length).fill(0).map(((t,e)=>e))}[Symbol.iterator](){const t=[];for(let e=0;e<this.length;e++)t[e]=this.get(e);return t[Symbol.iterator]()}}i=Symbol.toPrimitive,e.default=r},614:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0});const i=s(210),o=s(787),n=s(735),r=s(501);class h{get value(){const t={};for(const e in this.object)t[e]=this.object[e];return t}constructor(t,e,s=[],i){this.object={},this.propertyPath=s,this.multyx=t,this.editable=i,this.setterListeners=[],e instanceof h&&(e=e.value);for(const t in e instanceof o.EditWrapper?e.value:e)this.set(t,e instanceof o.EditWrapper?new o.EditWrapper(e.value[t]):e[t]);if(this.constructor===h)return new Proxy(this,{has:(t,e)=>t.has(e),get:(t,e)=>e in t?t[e]:t.get(e),set:(t,e,s)=>e in t?(t[e]=s,!0):t.set(e,s),deleteProperty:(t,e)=>t.delete(e,!1)})}has(t){return t in this.object}get(t){return this.object[t]}set(t,e){if(void 0===e)return this.delete(t);if(this.object[t]instanceof r.default)return this.object[t].set(e);if(e instanceof o.EditWrapper&&void 0===e.value)return this.delete(t,!0);if(!(e instanceof o.EditWrapper||this.editable))return this.multyx.options.verbose&&console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join(".")+"."+t}' to ${e}`),!1;this.object[t]=new((0,n.default)(e instanceof o.EditWrapper?e.value:e))(this.multyx,e,[...this.propertyPath,t],this.editable);for(const e of this.setterListeners)this.multyx[o.Add]((()=>{this.has(t)&&e(t,this.get(t))}));return e instanceof o.EditWrapper||this.multyx.ws.send(i.Message.Native({instruction:"edit",path:this.propertyPath,value:this.object[t].value})),!0}delete(t,e=!1){return this.editable||e?(delete this.object[t],e||this.multyx.ws.send(i.Message.Native({instruction:"edit",path:[...this.propertyPath,t],value:void 0})),!0):(this.multyx.options.verbose&&console.error(`Attempting to delete property that is not editable. Deleting '${this.propertyPath.join(".")+"."+t}'`),!1)}forAll(t){for(let e in this.object)t(e,this.get(e));this.setterListeners.push(t)}keys(){return Object.keys(this.object)}values(){return Object.values(this.object)}entries(){const t=[];for(let e in this.object)t.push([e,this.get(e)]);return t}[o.Unpack](t){for(const e in t)this.object[e][o.Unpack](t[e])}}e.default=h},735:(t,e,s)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(t){return Array.isArray(t)?s(70).default:"object"==typeof t?s(614).default:s(501).default}},501:(t,e,s)=>{var i;Object.defineProperty(e,"__esModule",{value:!0});const o=s(210),n=s(787);class r{get value(){return this.interpolator?this.interpolator.get():this._value}set value(t){this._value=t,this.interpolator&&this.interpolator.set()}constructor(t,e,s=[],o){this.toString=()=>this.value.toString(),this.valueOf=()=>this.value,this[i]=()=>this.value,this.propertyPath=s,this.editable=o,this.multyx=t,this.constraints={},this.set(e)}set(t){if(t instanceof n.EditWrapper)return this.value=t.value,!0;if(!this.editable)return this.multyx.options.verbose&&console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join(".")}' to ${t}`),!1;let e=t;for(const s in this.constraints)if(e=(0,this.constraints[s])(e),null===e)return this.multyx.options.verbose&&console.error(`Attempting to set property that failed on constraint. Setting '${this.propertyPath.join(".")}' to ${t}, stopped by constraint '${s}'`),!1;return this.value===e?(this.value=e,!0):(this.value=e,this.multyx.ws.send(o.Message.Native({instruction:"edit",path:this.propertyPath,value:e})),!0)}[n.Unpack](t){for(const[e,s]of Object.entries(t)){const t=(0,n.BuildConstraint)(e,s);t&&(this.constraints[e]=t)}}Lerp(){this.interpolator={history:[{value:this._value,time:Date.now()},{value:this._value,time:Date.now()}],get:()=>{const[t,e]=this.interpolator.history,s=Math.min(1,(Date.now()-t.time)/Math.min(250,t.time-e.time));return Number.isNaN(s)||"number"!=typeof t.value||"number"!=typeof e.value?t.value:t.value*s+e.value*(1-s)},set:()=>{this.interpolator.history.pop(),this.interpolator.history.unshift({value:this._value,time:Date.now()})}}}PredictiveLerp(){this.interpolator={history:[{value:this._value,time:Date.now()},{value:this._value,time:Date.now()},{value:this._value,time:Date.now()}],get:()=>{const[t,e,s]=this.interpolator.history,i=Math.min(1,(Date.now()-t.time)/(t.time-e.time));return Number.isNaN(i)||"number"!=typeof s.value||"number"!=typeof t.value||"number"!=typeof e.value||Math.abs((t.value-e.value)/(e.value-s.value)-1)>.2?t.value:t.value*(1+i)-e.value*i},set:()=>{this.interpolator.history.pop(),this.interpolator.history.unshift({value:this._value,time:Date.now()})}}}}i=Symbol.toPrimitive,e.default=r},210:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Message=void 0;class s{constructor(t,e,s=!1){this.name=t,this.data=e,this.time=Date.now(),this.native=s}static BundleOperations(t,e){return Array.isArray(e)||(e=[e]),JSON.stringify(new s("_",{operations:e,deltaTime:t}))}static Native(t){return JSON.stringify(new s("_",t,!0))}static Parse(t){const e=JSON.parse(t);return"_"==e.name[0]&&(e.name=e.name.slice(1)),new s(e.name,e.data,""==e.name)}static Create(t,e){if(0==t.length)throw new Error("Multyx message cannot have empty name");if("_"==t[0]&&(t="_"+t),"function"==typeof e)throw new Error("Multyx data must be JSON storable");return JSON.stringify(new s(t,e))}}e.Message=s},944:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultOptions=void 0,e.DefaultOptions={port:8443,secure:!1,uri:"localhost",verbose:!1,logUpdateFrame:!1}},787:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.EditWrapper=e.Add=e.Done=e.Unpack=void 0,e.Interpolate=function(t,e,s){let i={value:t[e],time:Date.now()},o={value:t[e],time:Date.now()};Object.defineProperty(t,e,{get:()=>{const t=o.time-i.time;let e=s[0],n=s[0];for(const i of s)t>i.time&&i.time>e.time&&(e=i),t<i.time&&i.time<n.time&&(n=i);const r=(t-e.time)/(n.time-e.time),h=e.progress+r*(n.progress-e.progress);return Number.isNaN(h)?i.value:o.value*h+i.value*(1-h)},set:t=>Date.now()-o.time<10?(o.value=t,!0):(i=Object.assign({},o),o={value:t,time:Date.now()},!0)})},e.BuildConstraint=function(t,e){return"min"==t?t=>t>=e[0]?t:e[0]:"max"==t?t=>t<=e[0]?t:e[0]:"int"==t?t=>Math.floor(t):"ban"==t?t=>e.includes(t)?null:t:"disabled"==t?t=>e[0]?null:t:t=>t},e.Unpack=Symbol("unpack"),e.Done=Symbol("done"),e.Add=Symbol("add"),e.EditWrapper=class{constructor(t){this.value=t}}}},e={};function s(i){var o=e[i];if(void 0!==o)return o.exports;var n=e[i]={exports:{}};return t[i](n,n.exports,s),n.exports}var i={};return(()=>{var t=i;const e=s(210),o=s(787),n=s(376),r=s(34),h=s(944);class l{constructor(t={},s){this.options=Object.assign(Object.assign({},h.DefaultOptions),t);const i=`ws${this.options.secure?"s":""}://${this.options.uri}:${this.options.port}/`;this.ws=new WebSocket(i),this.ping=0,this.events=new Map,this.self={},this.all={},this.teams={},this.clients={},this.controller=new n.Controller(this.ws),this.listenerQueue=[],null==s||s(),this.ws.onmessage=t=>{var s,i,o;const n=e.Message.Parse(t.data);this.ping=2*(Date.now()-n.time),n.native?(this.parseNativeEvent(n),null===(s=this.events.get(l.Native))||void 0===s||s.forEach((t=>t(n)))):n.name in this.events&&(this.events[n.name](n.data),null===(i=this.events.get(l.Custom))||void 0===i||i.forEach((t=>t(n)))),null===(o=this.events.get(l.Any))||void 0===o||o.forEach((t=>t(n)))}}on(t,e){var s;const i=null!==(s=this.events.get(t))&&void 0!==s?s:[];i.push(e),this.events.set(t,i)}send(t,s,i=!1){if("_"===t[0]&&(t="_"+t),this.ws.send(e.Message.Create(t,s)),i)return new Promise((e=>this.events.set(Symbol.for("_"+t),[e])))}loop(t,e){if(e)this.on(l.Start,(()=>setInterval(t,Math.round(1e3/e))));else{const e=()=>{t(),requestAnimationFrame(e)};this.on(l.Start,(()=>requestAnimationFrame(e)))}}forAll(t){this.on(l.Start,(()=>{this.teams.all.clients.forAll((e=>t(this.clients[e])))})),this.on(l.Connection,t)}parseNativeEvent(t){var e,s,i,o;this.options.logUpdateFrame&&console.log(t);for(const n of t.data)switch(n.instruction){case"init":this.initialize(n);for(const t of null!==(e=this.events.get(l.Start))&&void 0!==e?e:[])this.listenerQueue.push((()=>t(n)));this.events.has(l.Start)&&(this.events.get(l.Start).length=0);break;case"edit":this.parseEdit(n);for(const t of null!==(s=this.events.get(l.Edit))&&void 0!==s?s:[])this.listenerQueue.push((()=>t(n)));break;case"self":this.parseSelf(n);break;case"conn":this.clients[n.uuid]=new r.MultyxClientObject(this,n.data,[n.uuid],!1);for(const t of null!==(i=this.events.get(l.Connection))&&void 0!==i?i:[])this.listenerQueue.push((()=>t(this.clients[n.uuid])));break;case"dcon":for(const t of null!==(o=this.events.get(l.Disconnect))&&void 0!==o?o:[]){const e=this.clients[n.client].value;this.listenerQueue.push((()=>t(e)))}delete this.clients[n.client];break;case"resp":(0,this.events.get(Symbol.for("_"+n.name))[0])(n.response);break;default:this.options.verbose&&console.error("Server error: Unknown native Multyx instruction")}this.listenerQueue.forEach((t=>t())),this.listenerQueue.length=0}initialize(t){this.uuid=t.client.uuid,this.joinTime=t.client.joinTime,this.controller.listening=new Set(t.client.controller),this.teams=new r.MultyxClientObject(this,{},[],!0);for(const e of Object.keys(t.teams))this.teams[e]=new o.EditWrapper(t.teams[e]);this.all=this.teams.all,this.clients={};for(const[e,s]of Object.entries(t.clients))e!=this.uuid&&(this.clients[e]=new r.MultyxClientObject(this,new o.EditWrapper(s),[e],!1));const e=new r.MultyxClientObject(this,new o.EditWrapper(t.client.self),[this.uuid],!0);this.self=e,this.clients[this.uuid]=e;for(const[e,s]of Object.entries(t.constraintTable))(this.uuid==e?this.self:this.teams[e])[o.Unpack](s)}parseEdit(t){let e=t.team?this.teams:this.clients;if(e){for(const s of t.path.slice(0,-1))s in e||(e[s]=new o.EditWrapper({})),e=e[s];e[t.path.slice(-1)[0]]=new o.EditWrapper(t.value)}}parseSelf(t){if("controller"==t.prop)this.controller.listening=new Set(t.data);else if("uuid"==t.prop)this.uuid=t.data;else if("constraint"==t.prop){let e=this.uuid==t.data.path[0]?this.self:this.teams[t.data.path[0]];for(const s of t.data.path.slice(1))e=null==e?void 0:e[s];if(void 0===e)return;e[o.Unpack]({[t.data.name]:t.data.args})}}[o.Add](t){this.listenerQueue.push(t)}}l.Start=Symbol("start"),l.Connection=Symbol("connection"),l.Disconnect=Symbol("disconnect"),l.Edit=Symbol("edit"),l.Native=Symbol("native"),l.Custom=Symbol("custom"),l.Any=Symbol("any"),t.default=l})(),i.default})()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multyx-client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework designed to simplify the creation of multiplayer browser games by addressing the complexities of managing server-client communication, shared state, and input handling",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/options.ts CHANGED
@@ -7,7 +7,7 @@ export type Options = {
7
7
  };
8
8
 
9
9
  export const DefaultOptions: Options = {
10
- port: 443,
10
+ port: 8443,
11
11
  secure: false,
12
12
  uri: 'localhost',
13
13
  verbose: false,
package/tsconfig.json CHANGED
@@ -3,6 +3,7 @@
3
3
  "target": "es6", // Specify the target ECMAScript version.
4
4
  "lib": ["es2017", "dom"],
5
5
  "module": "commonjs", // Do not use any module system (for browser use).
6
+ "declaration": true,
6
7
  "outDir": "./dist",
7
8
  "rootDir": "./src", // Specify the root directory of your TypeScript source files.
8
9
  }