From 7a0ee5cc1ef02e7282c94d7e1a3d642e74e546ff Mon Sep 17 00:00:00 2001 From: Steven Vergenz Date: Tue, 28 Jan 2020 14:54:17 -0800 Subject: [PATCH] Convert all our IDs from strings to validated GUIDs (#476) * Start converting actor IDs to Guids * More updates to actorId * Convert actor network messages * Start converting assets/containers * Finish converting assets/containers * Update user, client, message * Convert mediaInstances * Fix tests and other packages * Remove another zeros check * Don't throw --- .../src/videoPlayerManager.ts | 7 +- packages/functional-tests/src/app.ts | 6 +- .../src/tests/clock-sync-test.ts | 2 +- .../src/tests/physics-sim-test.ts | 10 +- packages/sdk/src/adapters/multipeer/client.ts | 9 +- .../multipeer/protocols/clientExecution.ts | 2 +- .../multipeer/protocols/clientSync.ts | 5 +- packages/sdk/src/adapters/multipeer/rules.ts | 52 ++++----- .../sdk/src/adapters/multipeer/session.ts | 94 +++++++-------- .../sdk/src/adapters/multipeer/syncActor.ts | 8 +- .../src/adapters/multipeer/syncAnimation.ts | 2 +- .../sdk/src/adapters/multipeer/syncAsset.ts | 6 +- packages/sdk/src/animation/animation.ts | 4 +- packages/sdk/src/animation/animationState.ts | 3 +- packages/sdk/src/connection/connection.ts | 4 +- .../sdk/src/connection/eventedConnection.ts | 4 +- packages/sdk/src/connection/nullConnection.ts | 5 +- packages/sdk/src/protocols/protocol.ts | 27 +++-- packages/sdk/src/rpc/rpc.ts | 8 +- packages/sdk/src/types/internal/context.ts | 110 +++++++++--------- packages/sdk/src/types/network/message.ts | 5 +- .../sdk/src/types/network/payloads/assets.ts | 11 +- .../src/types/network/payloads/payloads.ts | 41 ++++--- .../sdk/src/types/network/payloads/physics.ts | 18 ++- packages/sdk/src/types/runtime/actor.ts | 39 +++---- packages/sdk/src/types/runtime/appearance.ts | 20 ++-- .../sdk/src/types/runtime/assets/asset.ts | 6 +- .../types/runtime/assets/assetContainer.ts | 35 +++--- .../sdk/src/types/runtime/assets/material.ts | 12 +- packages/sdk/src/types/runtime/attachment.ts | 4 +- .../sdk/src/types/runtime/behaviors/action.ts | 4 +- .../types/runtime/behaviors/actionEvent.ts | 3 +- packages/sdk/src/types/runtime/context.ts | 18 ++- packages/sdk/src/types/runtime/lookAt.ts | 4 +- .../sdk/src/types/runtime/mediaInstance.ts | 18 +-- .../src/types/runtime/physics/collision.ts | 4 +- .../types/runtime/physics/collisionEvent.ts | 3 +- .../src/types/runtime/physics/triggerEvent.ts | 5 +- packages/sdk/src/types/runtime/user.ts | 10 +- 39 files changed, 316 insertions(+), 312 deletions(-) diff --git a/packages/altspacevr-extras/src/videoPlayerManager.ts b/packages/altspacevr-extras/src/videoPlayerManager.ts index f44d25b3a..c035676ff 100644 --- a/packages/altspacevr-extras/src/videoPlayerManager.ts +++ b/packages/altspacevr-extras/src/videoPlayerManager.ts @@ -5,6 +5,7 @@ import { Context, + Guid, User } from '@microsoft/mixed-reality-extension-sdk'; @@ -17,7 +18,7 @@ type Video = { url: string; basisTime: number }; */ export class VideoPlayerManager { - private videos = new Map(); + private videos = new Map(); constructor(private context: Context) { this.context.onUserJoined(this.userJoined); @@ -41,7 +42,7 @@ export class VideoPlayerManager { } }; - public play(actorId: string, url: string, startTime: number) { + public play(actorId: Guid, url: string, startTime: number) { if (!this.videos.has(actorId) || this.videos.get(actorId).url !== url) { const video = { url, basisTime: startTime - Date.now() / 1000.0 }; this.videos.set(actorId, video); @@ -55,7 +56,7 @@ export class VideoPlayerManager { } } - public stop(actorId: string) { + public stop(actorId: Guid) { if (this.videos.has(actorId)) { this.context.rpc.send({ procName: 'VideoPlay' diff --git a/packages/functional-tests/src/app.ts b/packages/functional-tests/src/app.ts index d6c7d8908..4ddc105ae 100644 --- a/packages/functional-tests/src/app.ts +++ b/packages/functional-tests/src/app.ts @@ -25,7 +25,7 @@ export class App { public assets: MRE.AssetContainer; private firstUser: MRE.User; - private _connectedUsers: { [id: string]: MRE.User } = {}; + private _connectedUsers = new Map(); public testResults: { [name: string]: boolean } = {}; private activeTestName: string; @@ -78,7 +78,7 @@ export class App { } private userJoined(user: MRE.User) { - this.connectedUsers[user.id] = user; + this.connectedUsers.set(user.id, user); if (!this.firstUser) { this.firstUser = user; if (this.params.autorun === 'true' || this.params.nomenu === 'true') { @@ -88,7 +88,7 @@ export class App { } private userLeft(user: MRE.User) { - delete this.connectedUsers[user.id]; + this.connectedUsers.delete(user.id); if (user === this.firstUser) { this.firstUser = this.context.users[0] || null; if (!this.firstUser) { diff --git a/packages/functional-tests/src/tests/clock-sync-test.ts b/packages/functional-tests/src/tests/clock-sync-test.ts index e1dd05814..8073b150a 100644 --- a/packages/functional-tests/src/tests/clock-sync-test.ts +++ b/packages/functional-tests/src/tests/clock-sync-test.ts @@ -104,7 +104,7 @@ export default class ClockSyncTest extends Test { return true; } - public createAnimatableDigit(name: string, digits: string, parentId: string): MRE.Actor { + public createAnimatableDigit(name: string, digits: string, parentId: MRE.Guid): MRE.Actor { return MRE.Actor.Create(this.app.context, { actor: { name, diff --git a/packages/functional-tests/src/tests/physics-sim-test.ts b/packages/functional-tests/src/tests/physics-sim-test.ts index c2677ff7d..6c38d49eb 100644 --- a/packages/functional-tests/src/tests/physics-sim-test.ts +++ b/packages/functional-tests/src/tests/physics-sim-test.ts @@ -19,7 +19,7 @@ export default class PhysicsSimTest extends Test { private collisionPegMat: MRE.Material; private disabledPegMat: MRE.Material; private ballMat: MRE.Material; - private collRefCount: { [id: string]: number } = {}; + private collRefCount = new Map(); private ballCount = 0; private counterPlane: MRE.Actor; @@ -116,15 +116,15 @@ export default class PhysicsSimTest extends Test { } }); peg.collider.onCollision('collision-enter', () => { - this.collRefCount[peg.id] = this.collRefCount[peg.id] + 1 || 1; - if (this.collRefCount[peg.id] > 0) { + this.collRefCount.set(peg.id, (this.collRefCount.get(peg.id) ?? 0) + 1); + if (this.collRefCount.get(peg.id) > 0) { peg.appearance.material = this.collisionPegMat; } }); peg.collider.onCollision('collision-exit', () => { - this.collRefCount[peg.id]--; - if (this.collRefCount[peg.id] === 0) { + this.collRefCount.set(peg.id, this.collRefCount.get(peg.id) - 1); + if (this.collRefCount.get(peg.id) === 0) { peg.appearance.material = this.defaultPegMat; } }); diff --git a/packages/sdk/src/adapters/multipeer/client.ts b/packages/sdk/src/adapters/multipeer/client.ts index 2b93cb35e..f7f5acad4 100644 --- a/packages/sdk/src/adapters/multipeer/client.ts +++ b/packages/sdk/src/adapters/multipeer/client.ts @@ -5,9 +5,8 @@ import { EventEmitter } from 'events'; import semver from 'semver'; -import UUID from 'uuid/v4'; import { ClientExecution, ClientSync, MissingRule, Rules, Session } from '.'; -import { Connection, Message } from '../..'; +import { Connection, Guid, Message, newGuid } from '../..'; import { log } from '../../log'; import * as Protocols from '../../protocols'; import * as Payloads from '../../types/network/payloads'; @@ -30,7 +29,7 @@ export type QueuedMessage = { export class Client extends EventEmitter { private static orderSequence = 0; - private _id: string; + private _id: Guid; private _session: Session; private _protocol: Protocols.Protocol; private _order: number; @@ -49,14 +48,14 @@ export class Client extends EventEmitter { public get queuedMessages() { return this._queuedMessages; } public get userExclusiveMessages() { return this._userExclusiveMessages; } - public userId: string; + public userId: Guid; /** * Creates a new Client instance */ constructor(private _conn: Connection, private _version: semver.SemVer) { super(); - this._id = UUID(); + this._id = newGuid(); this._order = Client.orderSequence++; this._leave = this.leave.bind(this); this._conn.on('close', this._leave); diff --git a/packages/sdk/src/adapters/multipeer/protocols/clientExecution.ts b/packages/sdk/src/adapters/multipeer/protocols/clientExecution.ts index 61761d830..d9c7166bd 100644 --- a/packages/sdk/src/adapters/multipeer/protocols/clientExecution.ts +++ b/packages/sdk/src/adapters/multipeer/protocols/clientExecution.ts @@ -69,7 +69,7 @@ export class ClientExecution extends Protocols.Protocol implements Protocols.Mid } public beforeRecv = (message: Message): Message => { - if (this.promises[message.replyToId]) { + if (this.promises.has(message.replyToId)) { // If we have a queued promise for this message, let it through return message; } else { diff --git a/packages/sdk/src/adapters/multipeer/protocols/clientSync.ts b/packages/sdk/src/adapters/multipeer/protocols/clientSync.ts index f4fc1145e..0f97756b4 100644 --- a/packages/sdk/src/adapters/multipeer/protocols/clientSync.ts +++ b/packages/sdk/src/adapters/multipeer/protocols/clientSync.ts @@ -3,9 +3,8 @@ * Licensed under the MIT License. */ -import UUID from 'uuid/v4'; import { Client, ClientDesyncPreprocessor, MissingRule, Rules, SyncActor } from '..'; -import { Message } from '../../..'; +import { Guid, Message, newGuid } from '../../..'; import { log } from '../../../log'; import * as Protocols from '../../../protocols'; import * as Payloads from '../../../types/network/payloads'; @@ -58,7 +57,7 @@ export class ClientSync extends Protocols.Protocol { * Handle the outgoing message according to the synchronization rules specified for this payload. */ public sendMessage(message: Message, promise?: ExportedPromise, timeoutSeconds?: number) { - message.id = message.id || UUID(); + message.id = message.id ?? newGuid(); const handling = this.handlingForMessage(message); switch (handling) { case 'allow': { diff --git a/packages/sdk/src/adapters/multipeer/rules.ts b/packages/sdk/src/adapters/multipeer/rules.ts index a50428a43..5aef95229 100644 --- a/packages/sdk/src/adapters/multipeer/rules.ts +++ b/packages/sdk/src/adapters/multipeer/rules.ts @@ -5,7 +5,7 @@ import deepmerge from 'deepmerge'; import { ActiveMediaInstance, Client, Session, SynchronizationStage } from '.'; -import { MediaCommand, Message, WebSocket } from '../..'; +import { Guid, MediaCommand, Message, WebSocket } from '../..'; import { log } from '../../log'; import * as Payloads from '../../types/network/payloads'; import { ExportedPromise } from '../../utils/exportedPromise'; @@ -79,7 +79,7 @@ export type Rule = { * to stop processing of the message. */ beforeQueueMessageForClient: ( - session: Session, client: Client, message: any, promise: ExportedPromise) => Message; + session: Session, client: Client, message: Message, promise: ExportedPromise) => Message; /** * Called twice before a message is sent: first to determine if a message is user-dependent * (it is queued until user-join if so), and second to determine if the joined user is the @@ -91,7 +91,7 @@ export type Rule = { * @returns `null` if the message does not depend on a user, `true` if it depends on the given * user, and `false` if it depends on a different user. */ - shouldSendToUser: (message: any, userId: string, session: Session, client: Client) => boolean | null; + shouldSendToUser: (message: Message, userId: Guid, session: Session, client: Client) => boolean | null; }; /** @@ -224,7 +224,7 @@ const CreateActorRule: Rule = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actor.id].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actor.id).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -297,7 +297,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: Client, message: Message ) => { - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor && (client.authoritative || syncActor.grabbedBy === client.id)) { const correctionPayload = message.payload; @@ -373,7 +373,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { return message; }, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actor.id].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actor.id).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -391,7 +391,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: Client, message: Message ) => { - const syncActor = session.actorSet[message.payload.actor.id]; + const syncActor = session.actorSet.get(message.payload.actor.id); if (syncActor && (client.authoritative || syncActor.grabbedBy === client.id)) { // Merge the update into the existing actor. session.cacheActorUpdateMessage(message); @@ -441,7 +441,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { }, client: { ...DefaultRule.client, - shouldSendToUser: (message: Message, userId: string, session: Session) => { + shouldSendToUser: (message: Message, userId, session: Session) => { // TODO: don't send animation updates when the animation targets only actors // the client doesn't care/know about. return true; @@ -541,7 +541,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -554,7 +554,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { if (message.payload.animationId) { session.cacheAnimationCreationRequest(message); } else { - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor) { const enabled = message.payload.initialState && !!message.payload.initialState.enabled; syncActor.createdAnimations = syncActor.createdAnimations || []; @@ -612,7 +612,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { message: Message ) => { for (const actorId of message.payload.actorIds) { - delete session.actorSet[actorId]; + session.actorSet.delete(actorId); } return message; } @@ -678,7 +678,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -688,7 +688,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { session: Session, message: Message ) => { - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor) { syncActor.activeInterpolations = syncActor.activeInterpolations || []; syncActor.activeInterpolations.push(deepmerge({}, message.payload)); @@ -732,7 +732,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { // Check that this is the authoritative client const exclusiveUser = message.payload.actors && message.payload.actors.length ? - session.actorSet[message.payload.actors[0].id].exclusiveToUser : + session.actorSet.get(message.payload.actors[0].id).exclusiveToUser : undefined; if (client.authoritative || client.userId && client.userId === exclusiveUser) { // Create no-op creation message. Implicit sync from initialization until they're updated @@ -775,7 +775,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { ) => { // Store the client id of the client that is performing the grab. const payload = message.payload; - const syncActor = session.actorSet[payload.targetId]; + const syncActor = session.actorSet.get(payload.targetId); if (syncActor && payload.actionName.toLowerCase() === 'grab' && (syncActor.grabbedBy === client.id || syncActor.grabbedBy === undefined) ) { @@ -843,7 +843,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } } @@ -883,7 +883,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -895,7 +895,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { ) => { // If the app enabled or disabled the animation, update our local sync state to match. if (message.payload.state.enabled !== undefined) { - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor) { const animation = session.findAnimation(syncActor, message.payload.animationName); if (animation) { @@ -911,10 +911,10 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { message: Message ) => { // Check that this is the authoritative client - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; if (client.authoritative || client.userId && client.userId === exclusiveUser) { // Check that the actor exists. - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor) { // If the animation was disabled on the client, notify other clients and also // update our local sync state. @@ -962,7 +962,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -972,7 +972,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { session: Session, message: Message ) => { - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor) { syncActor.behavior = message.payload.behaviorType; } else { @@ -995,7 +995,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { client: { ...DefaultRule.client, shouldSendToUser: (message: Message, userId, session, client) => { - const exclusiveUser = session.actorSet[message.payload.actorId].exclusiveToUser; + const exclusiveUser = session.actorSet.get(message.payload.actorId).exclusiveToUser; return exclusiveUser ? exclusiveUser === userId : null; } }, @@ -1005,7 +1005,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { session: Session, message: Message ) => { - const syncActor = session.actorSet[message.payload.actorId]; + const syncActor = session.actorSet.get(message.payload.actorId); if (syncActor) { syncActor.activeMediaInstances = syncActor.activeMediaInstances || []; let activeMediaInstance: ActiveMediaInstance; @@ -1077,7 +1077,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { } // Look up asset duration from cached assets - const asset = session.assetSet[message.payload.mediaAssetId]; + const asset = session.assetSet.get(message.payload.mediaAssetId); if (activeMediaInstance.message.payload.options.looping === true || activeMediaInstance.message.payload.options.paused === true || @@ -1116,7 +1116,7 @@ export const Rules: { [id in Payloads.PayloadType]: Rule } = { }, client: { ...DefaultRule.client, - shouldSendToUser: (message: Message, userId: string) => { + shouldSendToUser: (message: Message, userId) => { return message.payload.userId === userId; } } diff --git a/packages/sdk/src/adapters/multipeer/session.ts b/packages/sdk/src/adapters/multipeer/session.ts index 1604ceb69..92d291846 100644 --- a/packages/sdk/src/adapters/multipeer/session.ts +++ b/packages/sdk/src/adapters/multipeer/session.ts @@ -22,17 +22,15 @@ type AnimationCreationMessage = Message } = {}; - private _assetSet: { [id: string]: Partial } = {}; - private _assetCreatorSet: { [id: string]: AssetCreationMessage } = {}; + private _clientSet = new Map(); + private _actorSet = new Map>(); + private _assetSet = new Map>(); + private _assetCreatorSet = new Map(); /** Maps animation IDs to animation sync structs */ - private _animationSet: Map> - = new Map>(); + private _animationSet = new Map>(); /** Maps IDs of messages that can create animations to the messages themselves */ - private _animationCreatorSet: Map - = new Map(); - private _userSet: { [id: string]: Partial } = {}; + private _animationCreatorSet = new Map(); + private _userSet = new Map>(); private _protocol: Protocols.Protocol; private _disconnect: () => void; @@ -40,35 +38,33 @@ export class Session extends EventEmitter { public get sessionId() { return this._sessionId; } public get protocol() { return this._protocol; } public get clients() { - return Object.values(this._clientSet).sort((a, b) => a.order - b.order); + return [...this._clientSet.values()].sort((a, b) => a.order - b.order); } - public get actors() { return Object.values(this._actorSet); } - public get assets() { return Object.values(this._assetSet); } - public get assetCreators() { return Object.values(this._assetCreatorSet); } + public get actors() { return [...this._actorSet.values()]; } + public get assets() { return [...this._assetSet.values()]; } + public get assetCreators() { return [...this._assetCreatorSet.values()]; } public get animationSet() { return this._animationSet; } public get animations() { return this._animationSet.values(); } public get animationCreators() { return this._animationCreatorSet.values(); } - public get users() { return Object.values(this._userSet); } public get actorSet() { return this._actorSet; } public get assetSet() { return this._assetSet; } public get assetCreatorSet() { return this._assetCreatorSet; } public get userSet() { return this._userSet; } public get rootActors() { - return Object.values(this._actorSet) - .filter(actor => !this._actorSet[actor.actorId].initialization.message.payload.actor.parentId); + return this.actors.filter(a => !a.initialization.message.payload.actor.parentId); } public get authoritativeClient() { return this.clients.find(client => client.authoritative); } public get peerAuthoritative() { return this._peerAuthoritative; } - public client = (clientId: string) => this._clientSet[clientId]; - public actor = (actorId: string) => this._actorSet[actorId]; - public user = (userId: string) => this._userSet[userId]; - public childrenOf = (parentId: string) => { + public client = (clientId: Guid) => this._clientSet.get(clientId); + public actor = (actorId: Guid) => this._actorSet.get(actorId); + public user = (userId: Guid) => this._userSet.get(userId); + public childrenOf = (parentId: Guid) => { return this.actors.filter(actor => actor.initialization.message.payload.actor.parentId === parentId); }; - public creatableChildrenOf = (parentId: string) => { + public creatableChildrenOf = (parentId: Guid) => { return this.actors.filter(actor => actor.initialization.message.payload.actor.parentId === parentId && !!actor.initialization.message.payload.type); @@ -120,7 +116,7 @@ export class Session extends EventEmitter { */ public async join(client: Client) { try { - this._clientSet[client.id] = client; + this._clientSet.set(client.id, client); client.on('close', () => this.leave(client.id)); // Synchronize app state to the client. await client.join(this); @@ -140,10 +136,10 @@ export class Session extends EventEmitter { /** * Removes the client from the session */ - public leave(clientId: string) { + public leave(clientId: Guid) { try { - const client = this._clientSet[clientId]; - delete this._clientSet[clientId]; + const client = this._clientSet.get(clientId); + this._clientSet.delete(clientId); if (client) { // If the client is associated with a userId, inform app the user is leaving if (client.userId) { @@ -168,12 +164,13 @@ export class Session extends EventEmitter { } catch { } } - private setAuthoritativeClient(clientId: string) { - if (!this._clientSet[clientId]) { + private setAuthoritativeClient(clientId: Guid) { + const newAuthority = this._clientSet.get(clientId); + if (!newAuthority) { log.error('network', `[ERROR] setAuthoritativeClient: client ${clientId} does not exist.`); + return; } const oldAuthority = this.authoritativeClient; - const newAuthority = this._clientSet[clientId]; newAuthority.setAuthoritative(true); for (const client of this.clients.filter(c => c !== newAuthority)) { @@ -226,7 +223,7 @@ export class Session extends EventEmitter { public preprocessFromClient(client: Client, message: Message): Message { // Precaution: If we don't recognize this client, drop the message. - if (!this._clientSet[client.id]) { + if (!this._clientSet.has(client.id)) { return undefined; } if (message.payload && message.payload.type && message.payload.type.length) { @@ -266,7 +263,7 @@ export class Session extends EventEmitter { syncActor.initialization.message && syncActor.initialization.message.payload && syncActor.initialization.message.payload.actor) { - const parent = this._actorSet[syncActor.initialization.message.payload.actor.parentId]; + const parent = this._actorSet.get(syncActor.initialization.message.payload.actor.parentId); if (parent) { return this.isAnimating(parent); } @@ -275,15 +272,16 @@ export class Session extends EventEmitter { } public cacheInitializeActorMessage(message: InitializeActorMessage) { - let syncActor = this.actorSet[message.payload.actor.id]; + let syncActor = this.actorSet.get(message.payload.actor.id); if (!syncActor) { - const parent = this.actorSet[message.payload.actor.parentId]; - syncActor = this.actorSet[message.payload.actor.id] = { + const parent = this.actorSet.get(message.payload.actor.parentId); + syncActor = { actorId: message.payload.actor.id, exclusiveToUser: parent && parent.exclusiveToUser || message.payload.actor.exclusiveToUser, initialization: deepmerge({ message }, {}) }; + this.actorSet.set(message.payload.actor.id, syncActor); // update reserved actor init message with something the client can use } else if (syncActor.initialization.message.payload.type === 'x-reserve-actor') { // send real init message, but with session's initial actor state @@ -297,7 +295,7 @@ export class Session extends EventEmitter { } public cacheActorUpdateMessage(message: Message) { - const syncActor = this.actorSet[message.payload.actor.id]; + const syncActor = this.actorSet.get(message.payload.actor.id); if (syncActor) { // Merge the update into the existing actor. syncActor.initialization.message.payload.actor @@ -317,16 +315,17 @@ export class Session extends EventEmitter { } public cacheAssetCreationRequest(message: AssetCreationMessage) { - this.assetCreatorSet[message.id] = message; + this.assetCreatorSet.set(message.id, message); } - public cacheAssetCreation(assetId: string, creatorId: string, duration?: number) { - const syncAsset = this.assetSet[assetId] = { + public cacheAssetCreation(assetId: Guid, creatorId: Guid, duration?: number) { + const syncAsset = { id: assetId, creatorMessageId: creatorId, duration } as Partial; - const creator = this.assetCreatorSet[creatorId]; + this.assetSet.set(assetId, syncAsset); + const creator = this.assetCreatorSet.get(creatorId); // Updates are cached on send, creates are cached on receive, // so it's possible something was updated while it was loading. @@ -340,8 +339,7 @@ export class Session extends EventEmitter { } // update end times on playing media instances with the now-known duration - for (const actorId of Object.keys(this.actorSet)) { - const syncActor = this.actorSet[actorId]; + for (const syncActor of this.actorSet.values()) { for (const activeMediaInstance of (syncActor.activeMediaInstances || [])) { if (activeMediaInstance.message.payload.mediaAssetId !== assetId || activeMediaInstance.message.payload.options.looping === true || @@ -364,9 +362,11 @@ export class Session extends EventEmitter { } public cacheAssetUpdate(update: Message) { - const syncAsset = this.assetSet[update.payload.asset.id] = - this.assetSet[update.payload.asset.id] || { id: update.payload.asset.id }; - const creator = this.assetCreatorSet[syncAsset.creatorMessageId]; + if (!this.assetSet.has(update.payload.asset.id)) { + this.assetSet.set(update.payload.asset.id, { id: update.payload.asset.id }); + } + const syncAsset = this.assetSet.get(update.payload.asset.id); + const creator = this.assetCreatorSet.get(syncAsset.creatorMessageId); if (creator && creator.payload.type === 'create-asset') { // roll update into creation message @@ -384,16 +384,16 @@ export class Session extends EventEmitter { } } - public cacheAssetUnload(containerId: string) { + public cacheAssetUnload(containerId: Guid) { const creators = this.assetCreators.filter(c => c.payload.containerId === containerId); for (const creator of creators) { // un-cache creation message - delete this.assetCreatorSet[creator.id]; + this.assetCreatorSet.delete(creator.id); // un-cache created assets const assets = this.assets.filter(a => a.creatorMessageId === creator.id); for (const asset of assets) { - delete this.assetSet[asset.id]; + this.assetSet.delete(asset.id); } } } @@ -402,7 +402,7 @@ export class Session extends EventEmitter { this._animationCreatorSet.set(payload.id, payload); } - public cacheAnimationCreation(animId: Guid, creatorId: string, duration?: number) { + public cacheAnimationCreation(animId: Guid, creatorId: Guid, duration?: number) { this._animationSet.set(animId, { id: animId, creatorMessageId: creatorId, diff --git a/packages/sdk/src/adapters/multipeer/syncActor.ts b/packages/sdk/src/adapters/multipeer/syncActor.ts index 5cb3c05a3..136268bd3 100644 --- a/packages/sdk/src/adapters/multipeer/syncActor.ts +++ b/packages/sdk/src/adapters/multipeer/syncActor.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { BehaviorType, Message } from '../..'; +import { BehaviorType, Guid, Message } from '../..'; import * as Payloads from '../../types/network/payloads'; /** @hidden */ @@ -37,12 +37,12 @@ export type ActiveMediaInstance = { * @hidden */ export type SyncActor = { - actorId: string; + actorId: Guid; initialization: InitializeActor; createdAnimations: CreateAnimation[]; activeMediaInstances: ActiveMediaInstance[]; activeInterpolations: Payloads.InterpolateActor[]; behavior: BehaviorType; - grabbedBy: string; - exclusiveToUser: string; + grabbedBy: Guid; + exclusiveToUser: Guid; }; diff --git a/packages/sdk/src/adapters/multipeer/syncAnimation.ts b/packages/sdk/src/adapters/multipeer/syncAnimation.ts index 4d7008aa8..9121a6bae 100644 --- a/packages/sdk/src/adapters/multipeer/syncAnimation.ts +++ b/packages/sdk/src/adapters/multipeer/syncAnimation.ts @@ -10,7 +10,7 @@ import * as Payloads from '../../types/network/payloads'; export class SyncAnimation { public id: Guid; /** Used if animation was packaged with others, i.e. part of a prefab */ - public creatorMessageId: string; + public creatorMessageId: Guid; /** Used only with batch creation, as definition is updated for other */ public update: Message; /** Used only for runtime instances that need to know the duration of the asset */ diff --git a/packages/sdk/src/adapters/multipeer/syncAsset.ts b/packages/sdk/src/adapters/multipeer/syncAsset.ts index f5496f6e4..642d6b1ac 100644 --- a/packages/sdk/src/adapters/multipeer/syncAsset.ts +++ b/packages/sdk/src/adapters/multipeer/syncAsset.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. */ -import { Message } from '../..'; +import { Guid, Message } from '../..'; import * as Payloads from '../../types/network/payloads'; /** @hidden */ export class SyncAsset { - public id: string; + public id: Guid; /** Used if asset was packaged with other assets */ - public creatorMessageId: string; + public creatorMessageId: Guid; /** Used only with batch creation, as definition is updated for other */ public update: Message; /** Used only for runtime instances (like MediaInstances) that need to know the duration of the asset */ diff --git a/packages/sdk/src/animation/animation.ts b/packages/sdk/src/animation/animation.ts index a205be8b0..c7f4cae11 100644 --- a/packages/sdk/src/animation/animation.ts +++ b/packages/sdk/src/animation/animation.ts @@ -26,7 +26,7 @@ export interface AnimationLike { /** What happens when the animation hits the last frame */ wrapMode: AnimationWrapMode; /** The IDs of the actors targeted by this animation */ - targetActorIds: Readonly; + targetActorIds: Readonly; /** The length in seconds of the animation */ duration: number; @@ -141,7 +141,7 @@ export class Animation implements AnimationLike, Patchable { this.updateTimeout(); } - private _targetActorIds: string[] = []; + private _targetActorIds: Guid[] = []; /** @inheritdoc */ public get targetActorIds() { return Object.freeze([...this._targetActorIds]); } diff --git a/packages/sdk/src/animation/animationState.ts b/packages/sdk/src/animation/animationState.ts index 133f33145..838769111 100644 --- a/packages/sdk/src/animation/animationState.ts +++ b/packages/sdk/src/animation/animationState.ts @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ +import { Guid } from '..'; /** * Describes an animation state. @@ -10,7 +11,7 @@ export type AnimationState = { /** * The actor this animation state belongs to. */ - actorId: string; + actorId: Guid; /** * The name of the animation. */ diff --git a/packages/sdk/src/connection/connection.ts b/packages/sdk/src/connection/connection.ts index c017670f1..e6021663f 100644 --- a/packages/sdk/src/connection/connection.ts +++ b/packages/sdk/src/connection/connection.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { Message } from '..'; +import { Guid, Message } from '..'; import { ExponentialMovingAverage } from '../utils/exponentialMovingAverage'; import { QueuedPromise } from '../utils/queuedPromise'; import { TrackingClock } from '../utils/trackingClock'; @@ -34,7 +34,7 @@ export class ConnectionQuality { */ export interface Connection { readonly quality: ConnectionQuality; - readonly promises: { [id: string]: QueuedPromise }; + readonly promises: Map; /** A snapshot of this connection's bandwidth usage */ readonly statsReport: NetworkStatsReport; diff --git a/packages/sdk/src/connection/eventedConnection.ts b/packages/sdk/src/connection/eventedConnection.ts index 54e4e89cb..a2867d5db 100644 --- a/packages/sdk/src/connection/eventedConnection.ts +++ b/packages/sdk/src/connection/eventedConnection.ts @@ -5,7 +5,7 @@ import { EventEmitter } from 'events'; import { Connection, ConnectionQuality } from '.'; -import { Message } from '..'; +import { Guid, Message } from '..'; import { QueuedPromise } from '../utils/queuedPromise'; import { NetworkStatsReport, NetworkStatsTracker } from './networkStats'; @@ -14,7 +14,7 @@ import { NetworkStatsReport, NetworkStatsTracker } from './networkStats'; */ export class EventedConnection extends EventEmitter implements Connection { protected _quality = new ConnectionQuality(); - private _promises: { [id: string]: QueuedPromise } = {}; + private _promises = new Map(); public statsTracker = new NetworkStatsTracker(); private queuedMessages: Message[] = []; diff --git a/packages/sdk/src/connection/nullConnection.ts b/packages/sdk/src/connection/nullConnection.ts index b86880dca..ae61cccde 100644 --- a/packages/sdk/src/connection/nullConnection.ts +++ b/packages/sdk/src/connection/nullConnection.ts @@ -5,7 +5,8 @@ import { EventEmitter } from 'events'; import { Connection, ConnectionQuality, NetworkStatsReport } from '.'; -import { Message } from '..'; +import { Guid, Message } from '..'; +import { QueuedPromise } from '../utils/queuedPromise'; /** * @hidden @@ -18,7 +19,7 @@ export class NullConnection extends EventEmitter implements Connection { public get quality() { return this._quality; } /** @inheritdoc */ - public get promises() { return {}; } + public get promises(): Map { return null; } /** @inheritdoc */ public get statsReport(): NetworkStatsReport { diff --git a/packages/sdk/src/protocols/protocol.ts b/packages/sdk/src/protocols/protocol.ts index af9b8870a..d9710debf 100644 --- a/packages/sdk/src/protocols/protocol.ts +++ b/packages/sdk/src/protocols/protocol.ts @@ -4,8 +4,7 @@ */ import { EventEmitter } from 'events'; -import UUID from 'uuid/v4'; -import { Connection, Message } from '..'; +import { Connection, Guid, Message, newGuid } from '..'; import { log } from '../log'; import { Payload } from '../types/network/payloads'; import { ExportedPromise } from '../utils/exportedPromise'; @@ -71,7 +70,7 @@ export class Protocol extends EventEmitter { } public sendMessage(message: Message, promise?: ExportedPromise, timeoutSeconds?: number) { - message.id = message.id || UUID(); + message.id = message.id ?? newGuid(); // Run message through all the middlewares const middlewares = this.middlewares.slice(); @@ -101,10 +100,10 @@ export class Protocol extends EventEmitter { // Save the reply callback if (promise) { - this.promises[message.id] = { + this.promises.set(message.id, { promise, timeout: setReplyTimeout() - }; + }); } log.verbose('network', `${this.name} send id:${message.id.substr(0, 8)}, type:${message.payload.type}`); @@ -176,21 +175,21 @@ export class Protocol extends EventEmitter { } protected handleReplyMessage(message: Message) { - const queuedPromise = this.promises[message.replyToId]; + const queuedPromise = this.promises.get(message.replyToId); if (!queuedPromise) { this.missingPromiseForReplyMessage(message); } else { - delete this.promises[message.replyToId]; + this.promises.delete(message.replyToId); clearTimeout(queuedPromise.timeout); queuedPromise.promise.resolve(message.payload, message); } } - private rejectPromiseForMessage(messageId: string, reason?: any) { - const queuedPromise = this.promises[messageId]; - if (queuedPromise && queuedPromise.promise && queuedPromise.promise.reject) { + private rejectPromiseForMessage(messageId: Guid, reason?: any) { + const queuedPromise = this.promises.get(messageId); + if (queuedPromise?.promise?.reject) { try { clearTimeout(queuedPromise.timeout); } catch { } - try { delete this.promises[messageId]; } catch { } + try { this.promises.delete(messageId); } catch { } try { queuedPromise.promise.reject(reason); } catch { } } } @@ -205,8 +204,8 @@ export class Protocol extends EventEmitter { }; private onClose = () => { - Object.keys(this.promises).map(key => { - this.rejectPromiseForMessage(key, "Connection closed."); - }); + for (const id of this.promises.keys()) { + this.rejectPromiseForMessage(id, "Connection closed."); + } }; } diff --git a/packages/sdk/src/rpc/rpc.ts b/packages/sdk/src/rpc/rpc.ts index 35cfbe319..450f58568 100644 --- a/packages/sdk/src/rpc/rpc.ts +++ b/packages/sdk/src/rpc/rpc.ts @@ -4,14 +4,14 @@ */ /* eslint-disable max-classes-per-file */ -import { Context } from '..'; +import { Context, Guid } from '..'; import { AppToEngineRPC, EngineToAppRPC } from '../types/network/payloads'; /** * @hidden * Type defining an rpc handler function callback. */ -export type RPCHandler = (options: { userId: string }, ...args: any[]) => void; +export type RPCHandler = (options: { userId: Guid }, ...args: any[]) => void; /** * RPC interface. Able to send and receive RPC calls. @@ -40,7 +40,7 @@ export class RPC { options: { procName: string; channelName?: string; - userId?: string; + userId?: Guid; }, ...args: any[]) { this.context.internal.sendPayload({ @@ -52,7 +52,7 @@ export class RPC { } as AppToEngineRPC); } - public receive(procName: string, userId: string, ...args: any[]) { + public receive(procName: string, userId: Guid, ...args: any[]) { const handler = this.handlers.get(procName); if (handler) { handler({ userId }, ...args); diff --git a/packages/sdk/src/types/internal/context.ts b/packages/sdk/src/types/internal/context.ts index 395a2f059..095717122 100644 --- a/packages/sdk/src/types/internal/context.ts +++ b/packages/sdk/src/types/internal/context.ts @@ -2,14 +2,10 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ - -import UUID from 'uuid/v4'; - import { ActionEvent, Actor, ActorLike, - ActorSet, Animation, AnimationLike, AnimationWrapMode, @@ -25,15 +21,13 @@ import { Guid, MediaCommand, newGuid, - parseGuid, PerformanceStats, SetAnimationStateOptions, SetMediaStateOptions, TriggerEvent, User, UserLike, - UserSet, - ZeroGuidString as ZeroGuid, + ZeroGuid, } from '../..'; import * as Payloads from '../network/payloads'; @@ -53,8 +47,8 @@ import { MediaInstance } from '../runtime/mediaInstance'; * @hidden */ export class InternalContext { - public actorSet: ActorSet = {}; - public userSet: UserSet = {}; + public actorSet = new Map(); + public userSet = new Map(); public userGroupMapping: { [id: string]: number } = { default: 1 }; public assetContainers = new Set(); public animationSet: Map = new Map(); @@ -77,7 +71,7 @@ export class InternalContext { ...options, actor: { ...(options && options.actor), - id: UUID() + id: newGuid() }, type: 'create-empty' } as Payloads.CreateEmpty); @@ -91,14 +85,14 @@ export class InternalContext { ...options, actor: { ...(options && options.actor), - id: UUID() + id: newGuid() }, type: 'create-from-library' } as Payloads.CreateFromLibrary); } public CreateFromPrefab(options: { - prefabId: string; + prefabId: Guid; collisionLayer?: CollisionLayer; actor?: Partial; }): Actor { @@ -106,7 +100,7 @@ export class InternalContext { ...options, actor: { ...(options && options.actor), - id: UUID() + id: newGuid() }, type: 'create-from-prefab' } as Payloads.CreateFromPrefab); @@ -144,7 +138,7 @@ export class InternalContext { } for (const createdActorLike of replyPayload.actors) { - const createdActor = this.actorSet[createdActorLike.id]; + const createdActor = this.actorSet.get(createdActorLike.id); if (createdActor) { createdActor.internal.notifyCreated(success, replyPayload.result.message); } @@ -176,7 +170,7 @@ export class InternalContext { actor?: Partial; }): Actor { // create actor locally - options.actor = Actor.sanitize({ ...options.actor, id: UUID() }); + options.actor = Actor.sanitize({ ...options.actor, id: newGuid() }); this.updateActors(options.actor); const actor = this.context.actor(options.actor.id); @@ -213,8 +207,8 @@ export class InternalContext { return actor; } - public createAnimation(actorId: string, animationName: string, options: CreateAnimationOptions) { - const actor = this.actorSet[actorId]; + public createAnimation(actorId: Guid, animationName: string, options: CreateAnimationOptions) { + const actor = this.actorSet.get(actorId); if (!actor) { log.error('app', `Failed to create animation on ${animationName}. Actor ${actorId} not found.`); } @@ -267,11 +261,11 @@ export class InternalContext { } public setAnimationState( - actorId: string, + actorId: Guid, animationName: string, state: SetAnimationStateOptions ) { - const actor = this.actorSet[actorId]; + const actor = this.actorSet.get(actorId); if (!actor) { log.error('app', `Failed to set animation state on "${animationName}". Actor "${actorId}" not found.`); return; @@ -297,7 +291,7 @@ export class InternalContext { mediaInstance: MediaInstance, command: MediaCommand, options?: SetMediaStateOptions, - mediaAssetId?: string, + mediaAssetId?: Guid, ) { this.protocol.sendPayload({ type: 'set-media-state', @@ -310,12 +304,12 @@ export class InternalContext { } public animateTo( - actorId: string, + actorId: Guid, value: Partial, duration: number, curve: number[], ) { - const actor = this.actorSet[actorId]; + const actor = this.actorSet.get(actorId); if (!actor) { log.error('app', `Failed animateTo. Actor ${actorId} not found.`); } else if (!Array.isArray(curve) || curve.length !== 4) { @@ -325,7 +319,7 @@ export class InternalContext { this.protocol.sendPayload({ type: 'interpolate-actor', actorId, - animationName: UUID(), + animationName: newGuid().toString(), value, duration, curve, @@ -454,7 +448,7 @@ export class InternalContext { }); } - public sendDestroyActors(actorIds: string[]) { + public sendDestroyActors(actorIds: Guid[]) { if (actorIds.length) { this.protocol.sendPayload({ type: 'destroy-actors', @@ -470,19 +464,19 @@ export class InternalContext { if (!Array.isArray(sactors)) { sactors = [sactors]; } - const newActorIds: string[] = []; + const newActorIds: Guid[] = []; // Instantiate and store each actor. sactors.forEach(sactor => { - const isNewActor = !this.actorSet[sactor.id]; - const actor = isNewActor ? Actor.alloc(this.context, sactor.id) : this.actorSet[sactor.id]; - this.actorSet[sactor.id] = actor; + const isNewActor = !this.actorSet.get(sactor.id); + const actor = isNewActor ? Actor.alloc(this.context, sactor.id) : this.actorSet.get(sactor.id); + this.actorSet.set(sactor.id, actor); actor.copy(sactor); if (isNewActor) { newActorIds.push(actor.id); } }); newActorIds.forEach(actorId => { - const actor = this.actorSet[actorId]; + const actor = this.actorSet.get(actorId); this.context.emitter.emit('actor-created', actor); }); } @@ -515,36 +509,38 @@ export class InternalContext { }; public userJoined(suser: Partial) { - if (!this.userSet[suser.id]) { - const user = this.userSet[suser.id] = new User(this.context, suser.id); + if (!this.userSet.has(suser.id)) { + const user = new User(this.context, suser.id); + this.userSet.set(suser.id, user); user.copy(suser); this.context.emitter.emit('user-joined', user); } } - public userLeft(userId: string) { - const user = this.userSet[userId]; + public userLeft(userId: Guid) { + const user = this.userSet.get(userId); if (user) { - delete this.userSet[userId]; + this.userSet.delete(userId); this.context.emitter.emit('user-left', user); } } public updateUser(suser: Partial) { - const isNewUser = !this.userSet[suser.id]; - const user = isNewUser ? new User(this.context, suser.id) : this.userSet[suser.id]; - user.copy(suser); - this.userSet[user.id] = user; - if (isNewUser) { + let user = this.userSet.get(suser.id); + if (!user) { + user = new User(this.context, suser.id); + user.copy(suser); + this.userSet.set(user.id, user); this.context.emitter.emit('user-joined', user); } else { + user.copy(suser); this.context.emitter.emit('user-updated', user); } } public performAction(actionEvent: ActionEvent) { if (actionEvent.user) { - const targetActor = this.actorSet[actionEvent.targetId]; + const targetActor = this.actorSet.get(actionEvent.targetId); if (targetActor) { targetActor.internal.performAction(actionEvent); } @@ -552,8 +548,8 @@ export class InternalContext { } public collisionEventRaised(collisionEvent: CollisionEvent) { - const actor = this.actorSet[collisionEvent.colliderOwnerId]; - const otherActor = this.actorSet[(collisionEvent.collisionData.otherActorId)]; + const actor = this.actorSet.get(collisionEvent.colliderOwnerId); + const otherActor = this.actorSet.get((collisionEvent.collisionData.otherActorId)); if (actor && otherActor) { // Update the collision data to contain the actual other actor. collisionEvent.collisionData = { @@ -568,8 +564,8 @@ export class InternalContext { } public triggerEventRaised(triggerEvent: TriggerEvent) { - const actor = this.actorSet[triggerEvent.colliderOwnerId]; - const otherActor = this.actorSet[triggerEvent.otherColliderOwnerId]; + const actor = this.actorSet.get(triggerEvent.colliderOwnerId); + const otherActor = this.actorSet.get(triggerEvent.otherColliderOwnerId); if (actor && otherActor) { actor.internal.triggerEventRaised( triggerEvent.eventType, @@ -577,17 +573,17 @@ export class InternalContext { } } - public setAnimationStateEventRaised(actorId: string, animationName: string, state: SetAnimationStateOptions) { + public setAnimationStateEventRaised(actorId: Guid, animationName: string, state: SetAnimationStateOptions) { const actor = this.context.actor(actorId); if (actor) { actor.internal.setAnimationStateEventRaised(animationName, state); } } - public localDestroyActors(actorIds: string[]) { + public localDestroyActors(actorIds: Guid[]) { for (const actorId of actorIds) { - if (this.actorSet[actorId]) { - this.localDestroyActor(this.actorSet[actorId]); + if (this.actorSet.has(actorId)) { + this.localDestroyActor(this.actorSet.get(actorId)); } } } @@ -598,13 +594,13 @@ export class InternalContext { this.localDestroyActor(child); }); // Remove actor from _actors - delete this.actorSet[actor.id]; + this.actorSet.delete(actor.id); // Raise event this.context.emitter.emit('actor-destroyed', actor); } - public destroyActor(actorId: string) { - const actor = this.actorSet[actorId]; + public destroyActor(actorId: Guid) { + const actor = this.actorSet.get(actorId); if (actor) { // Tell engine to destroy the actor (will destroy all children too) this.sendDestroyActors([actorId]); @@ -613,7 +609,7 @@ export class InternalContext { } } - public sendRigidBodyCommand(actorId: string, payload: Payloads.Payload) { + public sendRigidBodyCommand(actorId: Guid, payload: Payloads.Payload) { this.protocol.sendPayload({ type: 'rigidbody-commands', actorId, @@ -621,8 +617,8 @@ export class InternalContext { } as Payloads.RigidBodyCommands); } - public setBehavior(actorId: string, newBehaviorType: BehaviorType) { - const actor = this.actorSet[actorId]; + public setBehavior(actorId: Guid, newBehaviorType: BehaviorType) { + const actor = this.actorSet.get(actorId); if (actor) { this.protocol.sendPayload({ type: 'set-behavior', @@ -632,12 +628,12 @@ export class InternalContext { } } - public lookupAsset(id: string): Asset { + public lookupAsset(id: Guid): Asset { if (id === ZeroGuid) { return null; } for (const c of this.assetContainers) { - if (c.assetsById[id]) { - return c.assetsById[id]; + if (c.assetsById.has(id)) { + return c.assetsById.get(id); } } } diff --git a/packages/sdk/src/types/network/message.ts b/packages/sdk/src/types/network/message.ts index dc2326953..d7cbe3b4f 100644 --- a/packages/sdk/src/types/network/message.ts +++ b/packages/sdk/src/types/network/message.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. */ +import { Guid } from '../..'; import { Payload } from './payloads'; /** @@ -13,12 +14,12 @@ export type Message = { /** * Unique id of this message. When sending, a new id will be assigned if not already so. */ - id?: string; + id?: Guid; /** * (Optional) If the client is replying to us, this is the id of the original message. */ - replyToId?: string; + replyToId?: Guid; /** * (Server to client) The time the server sent this message. In milliseconds. diff --git a/packages/sdk/src/types/network/payloads/assets.ts b/packages/sdk/src/types/network/payloads/assets.ts index a33041c9e..9125ab027 100644 --- a/packages/sdk/src/types/network/payloads/assets.ts +++ b/packages/sdk/src/types/network/payloads/assets.ts @@ -4,8 +4,7 @@ */ import { CreateActorCommon, Payload } from '.'; -import { ColliderType, CollisionLayer } from '../../runtime'; -import { AssetLike, AssetSource } from '../../runtime/assets'; +import { AssetLike, AssetSource, ColliderType, CollisionLayer, Guid } from '../../..'; export type CreateColliderType = ColliderType | 'none'; @@ -21,7 +20,7 @@ export type AssetPayloadType /** @hidden */ export type LoadAssets = Payload & { type: 'load-assets'; - containerId: string; + containerId: Guid; source: AssetSource; colliderType: CreateColliderType; }; @@ -29,7 +28,7 @@ export type LoadAssets = Payload & { /** @hidden */ export type CreateAsset = Payload & { type: 'create-asset'; - containerId: string; + containerId: Guid; definition: AssetLike; }; @@ -49,12 +48,12 @@ export type AssetUpdate = Payload & { /** @hidden */ export type CreateFromPrefab = CreateActorCommon & { type: 'create-from-prefab'; - prefabId: string; + prefabId: Guid; collisionLayer?: CollisionLayer; }; /** @hidden */ export type UnloadAssets = Payload & { type: 'unload-assets'; - containerId: string; + containerId: Guid; }; diff --git a/packages/sdk/src/types/network/payloads/payloads.ts b/packages/sdk/src/types/network/payloads/payloads.ts index c0c6c220b..adfd2b894 100644 --- a/packages/sdk/src/types/network/payloads/payloads.ts +++ b/packages/sdk/src/types/network/payloads/payloads.ts @@ -5,14 +5,18 @@ import { OperationResultCode, Trace } from '..'; import { + ActionState, + ActorLike, AnimationLike, + BehaviorType, CreateAnimationOptions, + Guid, MediaCommand, SetAnimationStateOptions, - SetMediaStateOptions + SetMediaStateOptions, + TransformLike, + UserLike, } from '../../..'; -import { ActorLike, TransformLike, UserLike } from '../../runtime'; -import { ActionState, BehaviorType } from '../../runtime/behaviors'; import { OperatingModel } from '../operatingModel'; import { AssetPayloadType } from './assets'; import { SyncPayloadType } from './sync'; @@ -150,7 +154,7 @@ export type HeartbeatReply = Payload & { export type AppToEngineRPC = Payload & { type: 'app2engine-rpc'; channelName?: string; - userId?: string; + userId?: Guid; procName: string; args: any[]; }; @@ -161,7 +165,7 @@ export type AppToEngineRPC = Payload & { export type EngineToAppRPC = Payload & { type: 'engine2app-rpc'; channelName?: string; - userId?: string; + userId?: Guid; procName: string; args: any[]; }; @@ -227,7 +231,7 @@ export type AnimationUpdate = Payload & { */ export type ActorCorrection = Payload & { type: 'actor-correction'; - actorId: string; + actorId: Guid; appTransform: TransformLike; }; @@ -237,7 +241,7 @@ export type ActorCorrection = Payload & { */ export type DestroyActors = Payload & { type: 'destroy-actors'; - actorIds: string[]; + actorIds: Guid[]; }; /** @@ -281,7 +285,7 @@ export type UserJoined = Payload & { */ export type UserLeft = Payload & { type: 'user-left'; - userId: string; + userId: Guid; }; /** @@ -300,8 +304,8 @@ export type UserUpdate = Payload & { */ export type PerformAction = Payload & { type: 'perform-action'; - userId: string; - targetId: string; + userId: Guid; + targetId: Guid; behaviorType: BehaviorType; actionName: string; actionState: ActionState; @@ -314,7 +318,7 @@ export type PerformAction = Payload & { */ export type SetBehavior = Payload & { type: 'set-behavior'; - actorId: string; + actorId: Guid; behaviorType: BehaviorType; }; @@ -324,7 +328,7 @@ export type SetBehavior = Payload & { */ export type CreateAnimation = Payload & CreateAnimationOptions & { type: 'create-animation'; - actorId: string; + actorId: Guid; animationId?: string; animationName: string; }; @@ -336,7 +340,7 @@ export type CreateAnimation = Payload & CreateAnimationOptions & { */ export type SetAnimationState = Payload & { type: 'set-animation-state'; - actorId: string; + actorId: Guid; animationName: string; state: SetAnimationStateOptions; }; @@ -357,12 +361,11 @@ export type SyncAnimations = Payload & { */ export type SetMediaState = Payload & { type: 'set-media-state'; - id: string; - actorId: string; - mediaAssetId: string; + id: Guid; + actorId: Guid; + mediaAssetId: Guid; mediaCommand: MediaCommand; options: SetMediaStateOptions; - }; /** @@ -371,7 +374,7 @@ export type SetMediaState = Payload & { */ export type InterpolateActor = Payload & { type: 'interpolate-actor'; - actorId: string; + actorId: Guid; animationName: string; value: Partial; duration: number; @@ -385,7 +388,7 @@ export type InterpolateActor = Payload & { */ export type ShowDialog = Payload & { type: 'show-dialog'; - userId: string; + userId: Guid; text: string; acceptInput?: boolean; }; diff --git a/packages/sdk/src/types/network/payloads/physics.ts b/packages/sdk/src/types/network/payloads/physics.ts index d0a8fa59c..7db3ad812 100644 --- a/packages/sdk/src/types/network/payloads/physics.ts +++ b/packages/sdk/src/types/network/payloads/physics.ts @@ -4,8 +4,14 @@ */ import { Payload } from '.'; -import { CollisionData, CollisionEventType, QuaternionLike, Vector3Like } from '../../..'; -import { TriggerEventType } from '../../runtime'; +import { + CollisionData, + CollisionEventType, + Guid, + TriggerEventType, + QuaternionLike, + Vector3Like +} from '../../..'; /** * @hidden @@ -13,7 +19,7 @@ import { TriggerEventType } from '../../runtime'; */ export type RigidBodyCommands = Payload & { type: 'rigidbody-commands'; - actorId: string; + actorId: Guid; commandPayloads: Payload[]; }; @@ -78,7 +84,7 @@ export type RigidBodyAddRelativeTorque = Payload & { */ export type CollisionEventRaised = Payload & { type: 'collision-event-raised'; - actorId: string; + actorId: Guid; eventType: CollisionEventType; collisionData: CollisionData; }; @@ -89,7 +95,7 @@ export type CollisionEventRaised = Payload & { */ export type TriggerEventRaised = Payload & { type: 'trigger-event-rasied'; - actorId: string; + actorId: Guid; eventType: TriggerEventType; - otherActorId: string; + otherActorId: Guid; }; diff --git a/packages/sdk/src/types/runtime/actor.ts b/packages/sdk/src/types/runtime/actor.ts index cbdffeaa1..d726624d1 100644 --- a/packages/sdk/src/types/runtime/actor.ts +++ b/packages/sdk/src/types/runtime/actor.ts @@ -41,7 +41,7 @@ import { SetAudioStateOptions, SetVideoStateOptions, Vector3Like, - ZeroGuidString as ZeroGuid, + ZeroGuid, } from '../..'; import { log } from '../../log'; @@ -59,8 +59,8 @@ import { ColliderGeometry } from './physics'; * Describes the properties of an Actor. */ export interface ActorLike { - id: string; - parentId: string; + id: Guid; + parentId: Guid; name: string; tag: string; @@ -69,7 +69,7 @@ export interface ActorLike { * of the User with the given ID. This value can only be set at actor creation. * Any actors parented to this actor will also be exclusive to the given user. */ - exclusiveToUser: string; + exclusiveToUser: Guid; subscriptions: SubscriptionType[]; transform: Partial; appearance: Partial; @@ -82,13 +82,6 @@ export interface ActorLike { grabbable: boolean; } -/** - * @hidden - */ -export interface ActorSet { - [id: string]: Actor; -} - /** * An actor represents an object instantiated on the host. */ @@ -103,7 +96,7 @@ export class Actor implements ActorLike, Patchable { private _name: string; private _tag: string; - private _exclusiveToUser: string; + private _exclusiveToUser: Guid; private _parentId = ZeroGuid; private _subscriptions: SubscriptionType[] = []; private _transform = new ActorTransform(); @@ -148,7 +141,7 @@ export class Actor implements ActorLike, Patchable { public get parentId() { return this._parentId; } public set parentId(value) { const parentActor = this.context.actor(value); - if (!value || value.startsWith('0000') || !parentActor) { + if (!value || !parentActor) { value = ZeroGuid; } if (parentActor && parentActor.exclusiveToUser && parentActor.exclusiveToUser !== this.exclusiveToUser) { @@ -169,7 +162,7 @@ export class Actor implements ActorLike, Patchable { } } - private constructor(private _context: Context, private _id: string) { + private constructor(private _context: Context, private _id: Guid) { // Actor patching: Observe the transform for changed values. observe({ target: this._transform, @@ -189,7 +182,7 @@ export class Actor implements ActorLike, Patchable { * @hidden * TODO - get rid of this. */ - public static alloc(context: Context, id: string): Actor { + public static alloc(context: Context, id: Guid): Actor { return new Actor(context, id); } @@ -240,7 +233,7 @@ export class Actor implements ActorLike, Patchable { * @param options.actor The initial state of the root actor. */ public static CreateFromPrefab(context: Context, options: { - prefabId: string; + prefabId: Guid; collisionLayer?: CollisionLayer; actor?: Partial; }): Actor; @@ -272,7 +265,7 @@ export class Actor implements ActorLike, Patchable { }): Actor; public static CreateFromPrefab(context: Context, options: { - prefabId?: string; + prefabId?: Guid; prefab?: Prefab; firstPrefabFrom?: Asset[]; collisionLayer?: CollisionLayer; @@ -509,10 +502,10 @@ export class Actor implements ActorLike, Patchable { * @param lookAtMode (Optional) How to face the target. @see LookUpMode. * @param backward (Optional) If true, actor faces away from target rather than toward. */ - public enableLookAt(actorOrActorId: Actor | string, mode?: LookAtMode, backward?: boolean) { + public enableLookAt(actorOrActorId: Actor | Guid, mode?: LookAtMode, backward?: boolean) { // Resolve the actorId value. let actorId = ZeroGuid; - if (typeof (actorOrActorId) === 'object' && actorOrActorId.id !== undefined) { + if (actorOrActorId instanceof Actor && actorOrActorId.id !== undefined) { actorId = actorOrActorId.id; } else if (typeof (actorOrActorId) === 'string') { actorId = actorOrActorId; @@ -543,8 +536,8 @@ export class Actor implements ActorLike, Patchable { * @param userOrUserId The User or id of user to attach to. * @param attachPoint Where on the user to attach. */ - public attach(userOrUserId: User | string, attachPoint: AttachPoint) { - const userId = typeof userOrUserId === 'string' ? userOrUserId : userOrUserId.id; + public attach(userOrUserId: User | Guid, attachPoint: AttachPoint) { + const userId = userOrUserId instanceof User ? userOrUserId.id : userOrUserId; if (!this._attachment) { // Actor patching: Observe the attachment for changed values. this._attachment = new Attachment(); @@ -617,7 +610,7 @@ export class Actor implements ActorLike, Patchable { * @param options Adjustments to pitch and volume, and other characteristics. */ public startSound( - soundAssetId: string, + soundAssetId: Guid, options: SetAudioStateOptions, ): MediaInstance { return new MediaInstance(this, soundAssetId).start(options); @@ -629,7 +622,7 @@ export class Actor implements ActorLike, Patchable { * @param options Adjustments to pitch and volume, and other characteristics. */ public startVideoStream( - videoStreamAssetId: string, + videoStreamAssetId: Guid, options: SetVideoStateOptions, ): MediaInstance { return new MediaInstance(this, videoStreamAssetId).start(options); diff --git a/packages/sdk/src/types/runtime/appearance.ts b/packages/sdk/src/types/runtime/appearance.ts index 794285822..165d85d56 100644 --- a/packages/sdk/src/types/runtime/appearance.ts +++ b/packages/sdk/src/types/runtime/appearance.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. */ -import { Actor, GroupMask, Material, Mesh } from '.'; -import { ZeroGuidString as ZeroGuid } from '../..'; +import { Actor, GroupMask, Mesh } from '.'; +import { Guid, ZeroGuid } from '../..'; export interface AppearanceLike { /** @@ -17,12 +17,12 @@ export interface AppearanceLike { /** * The ID of a previously-created [[Material]] asset. */ - materialId: string; + materialId: Guid; /** * The ID of a previously-created [[Mesh]] asset. */ - meshId: string; + meshId: Guid; } export class Appearance implements AppearanceLike { @@ -99,16 +99,16 @@ export class Appearance implements AppearanceLike { /** @returns A shared reference to this actor's material, or null if this actor has no material */ public get material() { - return this.actor.context.internal.lookupAsset(this._materialId) as Material; + return this.actor.context.internal.lookupAsset(this._materialId)?.material; } public set material(value) { - this.materialId = value && value.id || ZeroGuid; + this.materialId = value?.id ?? ZeroGuid; } /** @inheritdoc */ public get materialId() { return this._materialId; } public set materialId(value) { - if (!value || value.startsWith('0000')) { + if (!value) { value = ZeroGuid; } if (!this.actor.context.internal.lookupAsset(value)) { @@ -128,16 +128,16 @@ export class Appearance implements AppearanceLike { /** @returns A shared reference to this actor's mesh, or null if this actor has no mesh */ public get mesh() { - return this.actor.context.internal.lookupAsset(this._meshId) as Mesh; + return this.actor.context.internal.lookupAsset(this._meshId).mesh; } public set mesh(value) { - this.meshId = value && value.id || ZeroGuid; + this.meshId = value?.id ?? ZeroGuid; } /** @inheritdoc */ public get meshId() { return this._meshId; } public set meshId(value) { - if (!value || value.startsWith('0000')) { + if (!value) { value = ZeroGuid; } if (!this.actor.context.internal.lookupAsset(value)) { diff --git a/packages/sdk/src/types/runtime/assets/asset.ts b/packages/sdk/src/types/runtime/assets/asset.ts index 1187d71d6..48be5d961 100644 --- a/packages/sdk/src/types/runtime/assets/asset.ts +++ b/packages/sdk/src/types/runtime/assets/asset.ts @@ -18,7 +18,7 @@ import { VideoStream, VideoStreamLike } from '.'; -import { Actor } from '..'; +import { Actor, Guid } from '../../..'; /** * Instructions for how to load an asset. @@ -45,7 +45,7 @@ export interface AssetLike { /** * The unique id of this asset. Use this to reference this asset in actors, etc. */ - id: string; + id: Guid; /** * A human-readable string identifying the asset. Not required to be unique, but * can be referenced by name if it is. @@ -72,7 +72,7 @@ export interface AssetLike { /** The base class for all asset types. */ export abstract class Asset implements AssetLike { - private _id: string; + private _id: Guid; private _name: string; private _source: AssetSource; private _loadedPromise: Promise; diff --git a/packages/sdk/src/types/runtime/assets/assetContainer.ts b/packages/sdk/src/types/runtime/assets/assetContainer.ts index 674463c03..ed9bd7e2f 100644 --- a/packages/sdk/src/types/runtime/assets/assetContainer.ts +++ b/packages/sdk/src/types/runtime/assets/assetContainer.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. */ -import UUID from 'uuid/v4'; - import { Asset, AssetSource, Material, MaterialLike, @@ -14,8 +12,15 @@ import { Texture, TextureLike, VideoStream, VideoStreamLike } from '.'; -import { Context } from '..'; -import { PrimitiveDefinition, PrimitiveShape, Vector3Like } from '../../..'; +import { + Context, + Guid, + newGuid, + ReadonlyMap, + PrimitiveDefinition, + PrimitiveShape, + Vector3Like +} from '../../..'; import { log } from '../../../log'; import resolveJsonValues from '../../../utils/resolveJsonValues'; import * as Payloads from '../../network/payloads'; @@ -26,14 +31,14 @@ import * as Payloads from '../../network/payloads'; * files for their assets. */ export class AssetContainer { - private _id: string; - private _assets: { [id: string]: Asset } = {}; + private _id: Guid; + private _assets = new Map(); /** @hidden */ public get id() { return this._id; } /** A mapping of asset IDs to assets in this container */ - public get assetsById() { return Object.freeze({ ...this._assets }); } + public get assetsById() { return this._assets as ReadonlyMap; } /** A list of all assets in this container */ public get assets() { return Object.values(this._assets); } /** A list of all materials in this container */ @@ -49,7 +54,7 @@ export class AssetContainer { /** Create a new asset container */ public constructor(public context: Context) { - this._id = UUID(); + this._id = newGuid(); context.internal.assetContainers.add(this); } @@ -60,7 +65,7 @@ export class AssetContainer { */ public createMaterial(name: string, definition: Partial): Material { const mat = new Material(this, { - id: UUID(), + id: newGuid(), name, material: resolveJsonValues(definition) }); @@ -75,7 +80,7 @@ export class AssetContainer { */ public createTexture(name: string, definition: Partial): Texture { const tex = new Texture(this, { - id: UUID(), + id: newGuid(), name, texture: resolveJsonValues(definition) }); @@ -90,7 +95,7 @@ export class AssetContainer { */ public createSound(name: string, definition: Partial): Sound { const sound = new Sound(this, { - id: UUID(), + id: newGuid(), name, sound: resolveJsonValues(definition) }); @@ -105,7 +110,7 @@ export class AssetContainer { */ public createVideoStream(name: string, definition: Partial): VideoStream { const video = new VideoStream(this, { - id: UUID(), + id: newGuid(), name, videoStream: resolveJsonValues(definition) }); @@ -215,7 +220,7 @@ export class AssetContainer { */ public createPrimitiveMesh(name: string, definition: PrimitiveDefinition): Mesh { const mesh = new Mesh(this, { - id: UUID(), + id: newGuid(), name, mesh: { primitiveDefinition: definition @@ -257,7 +262,7 @@ export class AssetContainer { for (const def of response.assets) { def.source = source; const asset = Asset.Parse(this, def); - this._assets[def.id] = asset; + this._assets.set(def.id, asset); newAssets.push(asset); } return newAssets; @@ -287,7 +292,7 @@ export class AssetContainer { throw new Error("Cannot load new assets into an unloaded container!"); } - this._assets[asset.id] = asset; + this._assets.set(asset.id, asset); const reply = await this.sendPayloadAndGetReply({ type: 'create-asset', diff --git a/packages/sdk/src/types/runtime/assets/material.ts b/packages/sdk/src/types/runtime/assets/material.ts index b6129ec8c..6ad63c51a 100644 --- a/packages/sdk/src/types/runtime/assets/material.ts +++ b/packages/sdk/src/types/runtime/assets/material.ts @@ -4,7 +4,7 @@ */ import { Asset, AssetContainer, AssetLike, Texture } from '.'; -import { Actor, ZeroGuidString as ZeroGuid } from '../../..'; +import { Actor, Guid, ZeroGuid } from '../../..'; import { Color3, Color4, Color4Like, Vector2, Vector2Like } from '../../../math'; import { observe } from '../../../utils/observe'; import readPath from '../../../utils/readPath'; @@ -18,7 +18,7 @@ export interface MaterialLike { /** The base color of this material. */ color: Partial; /** The main (albedo) texture asset ID */ - mainTextureId: string; + mainTextureId: Guid; /** The main texture's offset from default */ mainTextureOffset: Vector2Like; /** The main texture's scale from default */ @@ -51,7 +51,7 @@ export enum AlphaMode { */ export class Material extends Asset implements MaterialLike, Patchable { private _color = Color4.FromColor3(Color3.White(), 1.0); - private _mainTextureId: string = ZeroGuid; + private _mainTextureId = ZeroGuid; private _mainTextureOffset = Vector2.Zero(); private _mainTextureScale = Vector2.One(); private _alphaMode = AlphaMode.Opaque; @@ -67,16 +67,16 @@ export class Material extends Asset implements MaterialLike, Patchable this.internal.actorSet[actorId]); } - public get rootActors() { - return Object.keys(this.internal.actorSet) - .filter(actorId => !this.internal.actorSet[actorId].parent).map(actorId => this.internal.actorSet[actorId]); - } - public get users() { return Object.keys(this.internal.userSet).map(userId => this.internal.userSet[userId]); } + public get actors() { return [...this.internal.actorSet.values()]; } + public get rootActors() { return this.actors.filter(a => !a.parent); } + public get users() { return [...this.internal.userSet.values()]; } public get rpcChannels() { return this._rpcChannels; } public get rpc() { return this._rpc; } - public actor = (actorId: string): Actor => this.internal.actorSet[actorId]; - public user = (userId: string): User => this.internal.userSet[userId]; + public actor = (actorId: Guid): Actor => this.internal.actorSet.get(actorId); + public user = (userId: Guid): User => this.internal.userSet.get(userId); /** * Creates a new `Context` instance. */ constructor(settings: ContextSettings) { this._conn = settings.connection || new NullConnection(); - this._sessionId = settings.sessionId || UUID(); + this._sessionId = settings.sessionId || newGuid().toString(); this._internal = new InternalContext(this); this._rpcChannels = new RPCChannels(); this._rpc = new RPC(this); diff --git a/packages/sdk/src/types/runtime/lookAt.ts b/packages/sdk/src/types/runtime/lookAt.ts index 384384ac7..0c710328c 100644 --- a/packages/sdk/src/types/runtime/lookAt.ts +++ b/packages/sdk/src/types/runtime/lookAt.ts @@ -4,10 +4,10 @@ */ import { LookAtMode } from "../.."; -import { ZeroGuidString as ZeroGuid } from "../.."; +import { Guid, ZeroGuid } from "../.."; export interface LookAtLike { - actorId: string; + actorId: Guid; mode: LookAtMode; backward: boolean; } diff --git a/packages/sdk/src/types/runtime/mediaInstance.ts b/packages/sdk/src/types/runtime/mediaInstance.ts index 9f81bb3f6..403a8196a 100644 --- a/packages/sdk/src/types/runtime/mediaInstance.ts +++ b/packages/sdk/src/types/runtime/mediaInstance.ts @@ -3,10 +3,14 @@ * Licensed under the MIT License. */ -import UUID from 'uuid/v4'; -import { MediaCommand, SetMediaStateOptions } from '../..'; +import { + Actor, + Guid, + MediaCommand, + newGuid, + SetMediaStateOptions +} from '../..'; import { log } from '../../log'; -import { Actor } from './actor'; /** * A MediaInstance represents an instance managing the playback of a sound or video stream, @@ -14,12 +18,12 @@ import { Actor } from './actor'; */ export class MediaInstance { - public id: string; + public id: Guid; public actor: Actor; - private mediaAssetId: string; + private mediaAssetId: Guid; - constructor(actor: Actor, mediaAssetId: string) { - this.id = UUID(); + constructor(actor: Actor, mediaAssetId: Guid) { + this.id = newGuid(); this.actor = actor; this.mediaAssetId = mediaAssetId; } diff --git a/packages/sdk/src/types/runtime/physics/collision.ts b/packages/sdk/src/types/runtime/physics/collision.ts index d607dbf06..6d446be48 100644 --- a/packages/sdk/src/types/runtime/physics/collision.ts +++ b/packages/sdk/src/types/runtime/physics/collision.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { Actor, Vector3 } from "../../.."; +import { Actor, Guid, Vector3 } from "../../.."; /** * The collision handler to be called when a collision event occurs. @@ -36,7 +36,7 @@ export interface ContactPoint { * The collision data collected when a collision occurs. */ export interface CollisionData { - otherActorId: string; + otherActorId: Guid; otherActor?: Actor; contacts: ContactPoint[]; impulse: Vector3; diff --git a/packages/sdk/src/types/runtime/physics/collisionEvent.ts b/packages/sdk/src/types/runtime/physics/collisionEvent.ts index c9502ea4b..17e07a72d 100644 --- a/packages/sdk/src/types/runtime/physics/collisionEvent.ts +++ b/packages/sdk/src/types/runtime/physics/collisionEvent.ts @@ -4,12 +4,13 @@ */ import { CollisionData, CollisionEventType } from "."; +import { Guid } from '../../..'; /** * A collision event that has occured between physics objects. */ export interface CollisionEvent { - colliderOwnerId: string; + colliderOwnerId: Guid; eventType: CollisionEventType; collisionData: CollisionData; } diff --git a/packages/sdk/src/types/runtime/physics/triggerEvent.ts b/packages/sdk/src/types/runtime/physics/triggerEvent.ts index d019b3361..cfe5bf0d6 100644 --- a/packages/sdk/src/types/runtime/physics/triggerEvent.ts +++ b/packages/sdk/src/types/runtime/physics/triggerEvent.ts @@ -3,13 +3,14 @@ * Licensed under the MIT License. */ +import { Guid } from '../../..'; import { TriggerEventType } from "./collisionEventType"; /** * A trigger event that has occured between physics objects. */ export interface TriggerEvent { - colliderOwnerId: string; + colliderOwnerId: Guid; eventType: TriggerEventType; - otherColliderOwnerId: string; + otherColliderOwnerId: Guid; } diff --git a/packages/sdk/src/types/runtime/user.ts b/packages/sdk/src/types/runtime/user.ts index 9e45aebaf..d93559067 100644 --- a/packages/sdk/src/types/runtime/user.ts +++ b/packages/sdk/src/types/runtime/user.ts @@ -3,22 +3,18 @@ * Licensed under the MIT License. */ -import { Context, GroupMask } from '../..'; +import { Context, GroupMask, Guid } from '../..'; import readPath from '../../utils/readPath'; import { InternalUser } from '../internal/user'; import { Patchable } from '../patchable'; export interface UserLike { - id: string; + id: Guid; name: string; groups: number | GroupMask; properties: { [name: string]: string }; } -export interface UserSet { - [id: string]: User; -} - /** * The structure returned from [[User.prompt]]. */ @@ -77,7 +73,7 @@ export class User implements UserLike, Patchable { * PUBLIC METHODS */ - constructor(private _context: Context, private _id: string) { + constructor(private _context: Context, private _id: Guid) { this._internal = new InternalUser(this, this._context.internal); }