From 53a61fdeab4973cef7935cf8a8a7838421be6edd Mon Sep 17 00:00:00 2001 From: HexaField Date: Sat, 17 Aug 2024 10:07:15 +1000 Subject: [PATCH 1/5] only init physics if it's needed --- .../src/physics/systems/PhysicsSystem.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/spatial/src/physics/systems/PhysicsSystem.tsx b/packages/spatial/src/physics/systems/PhysicsSystem.tsx index 38bc9ff57c..b8f69ceb08 100755 --- a/packages/spatial/src/physics/systems/PhysicsSystem.tsx +++ b/packages/spatial/src/physics/systems/PhysicsSystem.tsx @@ -29,7 +29,7 @@ import { useEffect } from 'react' import { getComponent, removeComponent, useComponent } from '@etherealengine/ecs/src/ComponentFunctions' import { ECSState } from '@etherealengine/ecs/src/ECSState' import { Entity } from '@etherealengine/ecs/src/Entity' -import { QueryReactor, defineQuery } from '@etherealengine/ecs/src/QueryFunctions' +import { QueryReactor, defineQuery, useQuery } from '@etherealengine/ecs/src/QueryFunctions' import { defineSystem } from '@etherealengine/ecs/src/SystemFunctions' import { SimulationSystemGroup } from '@etherealengine/ecs/src/SystemGroups' import { getMutableState, getState, none, useHookstate } from '@etherealengine/hyperflux' @@ -115,6 +115,8 @@ const PhysicsSceneReactor = () => { const reactor = () => { const physicsLoaded = useHookstate(false) + const physicsLoadPending = useHookstate(false) + const physicsQuery = useQuery([SceneComponent]) useEffect(() => { const networkState = getMutableState(NetworkState) @@ -124,15 +126,21 @@ const reactor = () => { write: PhysicsSerialization.writeRigidBody }) - Physics.load().then(() => { - physicsLoaded.set(true) - }) - return () => { networkState.networkSchema[PhysicsSerialization.ID].set(none) } }, []) + useEffect(() => { + if (physicsLoaded.value || physicsLoadPending.value) return + if (physicsQuery.length) { + physicsLoadPending.set(true) + Physics.load().then(() => { + physicsLoaded.set(true) + }) + } + }, [physicsQuery]) + if (!physicsLoaded.value) return null return ( From 5f9141f4dd619206323b4d95993ec05b9126becc Mon Sep 17 00:00:00 2001 From: HexaField Date: Sat, 17 Aug 2024 11:40:14 +1000 Subject: [PATCH 2/5] move API to common package, move userID to hyperflux store --- packages/client-core/src/API.ts | 17 ++-- .../components/resources/ResourceTable.tsx | 4 +- .../admin/components/settings/tabs/client.tsx | 4 +- .../settings/tabs/instanceServer.tsx | 4 +- .../common/services/FileThumbnailJobState.tsx | 8 +- .../LocationInstanceConnectionService.ts | 18 ++--- .../MediaInstanceConnectionService.ts | 8 +- .../src/common/services/OEmbedService.ts | 4 +- .../src/common/services/ProjectService.ts | 54 ++++++------- .../src/common/services/RouterService.tsx | 6 +- .../src/social/services/ChannelService.ts | 27 ++++--- .../src/social/services/FriendService.ts | 22 +++--- .../src/social/services/InviteService.ts | 26 +++--- .../src/social/services/LocationService.ts | 16 ++-- .../components/UserMenu/menus/ProfileMenu.tsx | 3 +- .../src/user/services/AuthService.ts | 78 +++++++++--------- .../src/user/services/AvatarService.ts | 15 ++-- .../src/util/wait-for-client-authenticated.ts | 6 +- packages/client/src/engine.tsx | 58 +------------- packages/client/src/main.tsx | 6 +- packages/client/src/pages/AppPage.tsx | 2 - packages/client/src/pages/admin/index.tsx | 16 ++-- packages/client/src/pages/capture/capture.tsx | 10 ++- packages/client/src/pages/chat/chat.tsx | 20 +++-- packages/client/src/pages/editor/index.tsx | 11 ++- packages/client/src/pages/index.tsx | 2 - .../client/src/pages/location/location.tsx | 2 + packages/client/src/store.tsx | 79 +++++++++++++++++++ packages/common/index.ts | 1 + packages/common/src/API.ts | 6 ++ packages/ecs/src/Engine.ts | 37 +++++---- .../editor/src/components/EditorContainer.tsx | 5 +- .../assets/ModelCompressionPanel.tsx | 4 +- .../dialogs/CreatePrefabPanelDialog.tsx | 15 +--- .../realtime/EditorActiveInstanceService.ts | 6 +- .../functions/EditorControlFunctions.test.tsx | 2 +- .../editor/src/functions/assetFunctions.ts | 8 +- .../editor/src/functions/sceneFunctions.tsx | 14 ++-- .../compression/ModelTransformFunctions.ts | 10 +-- .../src/avatar/functions/moveAvatar.test.tsx | 9 ++- .../functions/spawnAvatarReceptor.test.tsx | 5 +- .../src/avatar/state/AvatarNetworkState.tsx | 7 +- .../systems/GrabbableSystem.test.ts | 2 +- .../src/recording/ECSRecordingSystem.ts | 11 +-- .../hyperflux/functions/StoreFunctions.ts | 17 +++- .../src/MediasoupRecordingSystem.ts | 4 +- .../instanceserver/src/NetworkFunctions.ts | 8 +- .../src/ServerHostNetworkSystem.tsx | 3 +- .../instanceserver/src/WebRTCFunctions.ts | 4 +- packages/instanceserver/src/channels.ts | 2 +- .../instanceserver/tests/InstanceLoad.test.ts | 5 +- .../network/src/EntityNetworkState.test.tsx | 14 ++-- packages/network/src/EntityNetworkState.tsx | 2 +- .../functions/NetworkPeerFunctions.test.tsx | 10 +-- .../src/serialization/DataReader.test.ts | 8 +- packages/projects/loadEngineInjection.ts | 4 +- packages/projects/loadWebappInjection.ts | 4 +- packages/server-core/src/createApp.ts | 13 ++- packages/spatial/src/EngineState.ts | 4 - .../src/camera/systems/CameraSystem.test.tsx | 2 +- .../camera/systems/SpectateSystem.test.tsx | 4 +- .../common/functions/FeathersHooks.test.ts | 21 ++--- .../src/common/functions/FeathersHooks.tsx | 8 +- .../src/common/functions/checkScope.ts | 4 +- .../editor/panels/Assets/container/index.tsx | 4 +- .../Files/browserGrid/FilePropertiesModal.tsx | 6 +- .../panels/Files/download/projectDownload.tsx | 4 +- .../panels/Materials/container/index.tsx | 9 +-- .../properties/model/transform/index.tsx | 6 +- .../ui/src/pages/Capture/index.stories.tsx | 2 +- 70 files changed, 451 insertions(+), 389 deletions(-) create mode 100755 packages/client/src/store.tsx create mode 100644 packages/common/index.ts create mode 100644 packages/common/src/API.ts diff --git a/packages/client-core/src/API.ts b/packages/client-core/src/API.ts index 1cd5d857c9..1de5829857 100755 --- a/packages/client-core/src/API.ts +++ b/packages/client-core/src/API.ts @@ -29,23 +29,24 @@ import feathers from '@feathersjs/client' import type { FeathersApplication } from '@feathersjs/feathers' import Primus from 'primus-client' +import { API as CommonAPI } from '@etherealengine/common' + import type { ServiceTypes } from '@etherealengine/common/declarations' import config from '@etherealengine/common/src/config' -import { Engine } from '@etherealengine/ecs/src/Engine' import primusClient from './util/primus-client' -export type FeathersClient = FeathersApplication & - AuthenticationClient & { - primus: Primus +declare module '@feathersjs/client' { + interface FeathersApplication extends AuthenticationClient { authentication: AuthenticationClient } +} -/**@deprecated - use 'Engine.instance.api' instead */ +/**@deprecated - use '@etherealengine.common API.instance' instead */ export class API { - /**@deprecated - use 'Engine.instance.api' instead */ + /**@deprecated - use '@etherealengine.common API.instance' instead */ static instance: API - client: FeathersClient + client: FeathersApplication static createAPI = () => { const feathersClient = feathers() @@ -66,7 +67,7 @@ export class API { API.instance = new API() API.instance.client = feathersClient as any - Engine.instance.api = feathersClient + CommonAPI.instance = feathersClient } } diff --git a/packages/client-core/src/admin/components/resources/ResourceTable.tsx b/packages/client-core/src/admin/components/resources/ResourceTable.tsx index 1b1ddc3509..28683c95c8 100644 --- a/packages/client-core/src/admin/components/resources/ResourceTable.tsx +++ b/packages/client-core/src/admin/components/resources/ResourceTable.tsx @@ -32,7 +32,7 @@ import { useFind, useSearch } from '@etherealengine/spatial/src/common/functions import ConfirmDialog from '@etherealengine/ui/src/components/tailwind/ConfirmDialog' import Button from '@etherealengine/ui/src/primitives/tailwind/Button' -import { Engine } from '@etherealengine/ecs' +import { API } from '@etherealengine/common' import { PopoverState } from '../../../common/services/PopoverState' import { resourceColumns } from '../../common/constants/resources' import DataTable from '../../common/Table' @@ -87,7 +87,7 @@ export default function ResourceTable({ search }: { search: string }) { { - await Engine.instance.api.service(staticResourcePath).remove(el.id) + await API.instance.service(staticResourcePath).remove(el.id) }} /> ) diff --git a/packages/client-core/src/admin/components/settings/tabs/client.tsx b/packages/client-core/src/admin/components/settings/tabs/client.tsx index 954b9926d7..7542603f42 100644 --- a/packages/client-core/src/admin/components/settings/tabs/client.tsx +++ b/packages/client-core/src/admin/components/settings/tabs/client.tsx @@ -37,7 +37,7 @@ import Select from '@etherealengine/ui/src/primitives/tailwind/Select' import Text from '@etherealengine/ui/src/primitives/tailwind/Text' import Toggle from '@etherealengine/ui/src/primitives/tailwind/Toggle' -import { Engine } from '@etherealengine/ecs' +import { API } from '@etherealengine/common' import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' const ClientTab = forwardRef(({ open }: { open: boolean }, ref: React.MutableRefObject) => { @@ -104,7 +104,7 @@ const ClientTab = forwardRef(({ open }: { open: boolean }, ref: React.MutableRef updatedAt: undefined! } as any as ClientSettingType - Engine.instance.api + API.instance .service(clientSettingPath) .patch(id, newSettings) .then(() => { diff --git a/packages/client-core/src/admin/components/settings/tabs/instanceServer.tsx b/packages/client-core/src/admin/components/settings/tabs/instanceServer.tsx index d7f1a0e2c6..26ac3e45e7 100644 --- a/packages/client-core/src/admin/components/settings/tabs/instanceServer.tsx +++ b/packages/client-core/src/admin/components/settings/tabs/instanceServer.tsx @@ -27,8 +27,8 @@ import React, { forwardRef, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { HiMinus, HiPlusSmall } from 'react-icons/hi2' +import { API } from '@etherealengine/common' import { instanceServerSettingPath, InstanceServerSettingType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs' import { NO_PROXY, State, useHookstate } from '@etherealengine/hyperflux' import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import PasswordInput from '@etherealengine/ui/src/components/tailwind/PasswordInput' @@ -79,7 +79,7 @@ const InstanceServerTab = forwardRef(({ open }: { open: boolean }, ref: React.Mu // } - Engine.instance.api + API.instance .service(instanceServerSettingPath) .patch(id, newSettings) .then(() => { diff --git a/packages/client-core/src/common/services/FileThumbnailJobState.tsx b/packages/client-core/src/common/services/FileThumbnailJobState.tsx index 148bac50a5..cd12069e6f 100644 --- a/packages/client-core/src/common/services/FileThumbnailJobState.tsx +++ b/packages/client-core/src/common/services/FileThumbnailJobState.tsx @@ -23,13 +23,13 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import { API } from '@etherealengine/common' import { FileBrowserContentType, fileBrowserUploadPath, staticResourcePath } from '@etherealengine/common/src/schema.type.module' import { - Engine, EntityUUID, UUIDComponent, UndefinedEntity, @@ -129,9 +129,7 @@ const uploadThumbnail = async (src: string, projectName: string, staticResourceI thumbnailURL.search = '' thumbnailURL.hash = '' const _thumbnailKey = thumbnailURL.href.replace(config.client.fileServer + '/', '') - await Engine.instance.api - .service(staticResourcePath) - .patch(staticResourceId, { thumbnailKey: _thumbnailKey, thumbnailMode }) + await API.instance.service(staticResourcePath).patch(staticResourceId, { thumbnailKey: _thumbnailKey, thumbnailMode }) } const seenResources = new Set() @@ -160,7 +158,7 @@ export const FileThumbnailJobState = defineState({ if (resource.type === 'thumbnail') { //set thumbnail's thumbnail as itself - Engine.instance.api.service(staticResourcePath).patch(resource.id, { thumbnailKey: resource.key }) + API.instance.service(staticResourcePath).patch(resource.id, { thumbnailKey: resource.key }) continue } diff --git a/packages/client-core/src/common/services/LocationInstanceConnectionService.ts b/packages/client-core/src/common/services/LocationInstanceConnectionService.ts index f5a98ed01e..6d4f9db498 100755 --- a/packages/client-core/src/common/services/LocationInstanceConnectionService.ts +++ b/packages/client-core/src/common/services/LocationInstanceConnectionService.ts @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import { Paginated } from '@feathersjs/feathers' import { useEffect } from 'react' +import { API } from '@etherealengine/common' import logger from '@etherealengine/common/src/logger' import { InstanceID, @@ -35,7 +36,6 @@ import { LocationID, RoomCode } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, getState, Identifiable, State, useState } from '@etherealengine/hyperflux' import { NetworkState } from '@etherealengine/network' @@ -84,7 +84,7 @@ export const LocationInstanceConnectionService = { logger.info({ locationId, instanceId, sceneId }, 'Provision World Server') const token = getState(AuthState).authUser.accessToken if (instanceId != null) { - const instance = (await Engine.instance.api.service(instancePath).find({ + const instance = (await API.instance.service(instancePath).find({ query: { id: instanceId, ended: false @@ -94,7 +94,7 @@ export const LocationInstanceConnectionService = { instanceId = null! } } - const provisionResult = await Engine.instance.api.service(instanceProvisionPath).find({ + const provisionResult = await API.instance.service(instanceProvisionPath).find({ query: { locationId, instanceId, @@ -124,7 +124,7 @@ export const LocationInstanceConnectionService = { provisionExistingServer: async (locationId: LocationID, instanceId: InstanceID, sceneId: string) => { logger.info({ locationId, instanceId, sceneId }, 'Provision Existing World Server') const token = getState(AuthState).authUser.accessToken - const instance = (await Engine.instance.api.service(instancePath).find({ + const instance = (await API.instance.service(instancePath).find({ query: { id: instanceId, ended: false @@ -140,7 +140,7 @@ export const LocationInstanceConnectionService = { } return } - const provisionResult = await Engine.instance.api.service(instanceProvisionPath).find({ + const provisionResult = await API.instance.service(instanceProvisionPath).find({ query: { locationId, instanceId, @@ -165,7 +165,7 @@ export const LocationInstanceConnectionService = { provisionExistingServerByRoomCode: async (locationId: LocationID, roomCode: RoomCode, sceneId: string) => { logger.info({ locationId, roomCode, sceneId }, 'Provision Existing World Server') const token = getState(AuthState).authUser.accessToken - const instance = (await Engine.instance.api.service(instancePath).find({ + const instance = (await API.instance.service(instancePath).find({ query: { roomCode, ended: false @@ -181,7 +181,7 @@ export const LocationInstanceConnectionService = { } return } - const provisionResult = await Engine.instance.api.service(instanceProvisionPath).find({ + const provisionResult = await API.instance.service(instanceProvisionPath).find({ query: { locationId, roomCode, @@ -219,10 +219,10 @@ export const LocationInstanceConnectionService = { }) } - Engine.instance.api.service(instanceProvisionPath).on('created', instanceProvisionCreatedListener) + API.instance.service(instanceProvisionPath).on('created', instanceProvisionCreatedListener) return () => { - Engine.instance.api.service(instanceProvisionPath).off('created', instanceProvisionCreatedListener) + API.instance.service(instanceProvisionPath).off('created', instanceProvisionCreatedListener) } }, []) } diff --git a/packages/client-core/src/common/services/MediaInstanceConnectionService.ts b/packages/client-core/src/common/services/MediaInstanceConnectionService.ts index a537840e3c..10ead0143c 100755 --- a/packages/client-core/src/common/services/MediaInstanceConnectionService.ts +++ b/packages/client-core/src/common/services/MediaInstanceConnectionService.ts @@ -25,9 +25,9 @@ Ethereal Engine. All Rights Reserved. import { useEffect } from 'react' +import { API } from '@etherealengine/common' import multiLogger from '@etherealengine/common/src/logger' import { ChannelID, InstanceID, instanceProvisionPath, RoomCode } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, getState, Identifiable, State, useState } from '@etherealengine/hyperflux' import { NetworkState } from '@etherealengine/network' @@ -70,7 +70,7 @@ export const MediaInstanceConnectionService = { provisionServer: async (channelID: ChannelID, createPrivateRoom = false) => { logger.info(`Provision Media Server, channelId: "${channelID}".`) const token = getState(AuthState).authUser.accessToken - const provisionResult = await Engine.instance.api.service(instanceProvisionPath).find({ + const provisionResult = await API.instance.service(instanceProvisionPath).find({ query: { channelId: channelID, token, @@ -103,9 +103,9 @@ export const MediaInstanceConnectionService = { }) } } - Engine.instance.api.service(instanceProvisionPath).on('created', listener) + API.instance.service(instanceProvisionPath).on('created', listener) return () => { - Engine.instance.api.service(instanceProvisionPath).off('created', listener) + API.instance.service(instanceProvisionPath).off('created', listener) } }, []) } diff --git a/packages/client-core/src/common/services/OEmbedService.ts b/packages/client-core/src/common/services/OEmbedService.ts index 1972d274d8..ca831fb34e 100644 --- a/packages/client-core/src/common/services/OEmbedService.ts +++ b/packages/client-core/src/common/services/OEmbedService.ts @@ -23,9 +23,9 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import { API } from '@etherealengine/common' import multiLogger from '@etherealengine/common/src/logger' import { oembedPath, OembedType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState } from '@etherealengine/hyperflux' import { NotificationService } from './NotificationService' @@ -42,7 +42,7 @@ export const OEmbedState = defineState({ fetchData: async (pathname: string, queryUrl: string) => { try { getMutableState(OEmbedState).merge({ oEmbed: undefined, pathname }) - const oEmbed = (await Engine.instance.api.service(oembedPath).find({ query: { url: queryUrl } })) as OembedType + const oEmbed = (await API.instance.service(oembedPath).find({ query: { url: queryUrl } })) as OembedType getMutableState(OEmbedState).merge({ oEmbed, pathname }) } catch (err) { logger.error(err) diff --git a/packages/client-core/src/common/services/ProjectService.ts b/packages/client-core/src/common/services/ProjectService.ts index b523bd65a6..a79d64c20d 100644 --- a/packages/client-core/src/common/services/ProjectService.ts +++ b/packages/client-core/src/common/services/ProjectService.ts @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import { Paginated } from '@feathersjs/feathers' import { useEffect } from 'react' +import { API } from '@etherealengine/common' import multiLogger from '@etherealengine/common/src/logger' import { builderInfoPath, @@ -48,7 +49,6 @@ import { ProjectUpdateParams, UserID } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, useHookstate } from '@etherealengine/hyperflux' import { NotificationService } from './NotificationService' @@ -79,7 +79,7 @@ export const ProjectState = defineState({ export const ProjectService = { fetchProjects: async () => { try { - const projects = (await Engine.instance.api.service(projectPath).find({ + const projects = (await API.instance.service(projectPath).find({ query: { action: 'admin', allowed: true @@ -96,14 +96,14 @@ export const ProjectService = { // restricted to admin scope createProject: async (name: string, params?: ProjectUpdateParams) => { - const result = await Engine.instance.api.service(projectPath).create({ name }, params) + const result = await API.instance.service(projectPath).create({ name }, params) logger.info({ result }, 'Create project result') await ProjectService.fetchProjects() }, // restricted to admin scope uploadProject: async (data: ProjectBuildUpdateItemType) => { - const result = await Engine.instance.api.service(projectPath).update('', { + const result = await API.instance.service(projectPath).update('', { sourceURL: data.sourceURL, destinationURL: data.destinationURL, name: data.name, @@ -114,20 +114,20 @@ export const ProjectService = { updateSchedule: data.updateSchedule }) logger.info({ result }, 'Upload project result') - await Engine.instance.api.service(projectInvalidatePath).patch(null, { projectName: data.name }) + await API.instance.service(projectInvalidatePath).patch(null, { projectName: data.name }) await ProjectService.fetchProjects() }, // restricted to admin scope removeProject: async (id: string, params?: ProjectUpdateParams) => { - const result = await Engine.instance.api.service(projectPath).remove(id, params) + const result = await API.instance.service(projectPath).remove(id, params) logger.info({ result }, 'Remove project result') await ProjectService.fetchProjects() }, // restricted to admin scope checkReloadStatus: async () => { - const result = await Engine.instance.api.service(projectBuildPath).find() + const result = await API.instance.service(projectBuildPath).find() logger.info({ result }, 'Check reload projects result') getMutableState(ProjectState).merge({ rebuilding: result.running, @@ -139,7 +139,7 @@ export const ProjectService = { // restricted to admin scope invalidateProjectCache: async (projectName: string) => { try { - await Engine.instance.api.service(projectInvalidatePath).patch(null, { projectName }) + await API.instance.service(projectInvalidatePath).patch(null, { projectName }) await ProjectService.fetchProjects() } catch (err) { logger.error(err, 'Error invalidating project cache.') @@ -148,7 +148,7 @@ export const ProjectService = { setEnabled: async (id: string, enabled: boolean) => { try { - await Engine.instance.api.service(projectPath).patch(id, { + await API.instance.service(projectPath).patch(id, { enabled }) } catch (err) { @@ -159,7 +159,7 @@ export const ProjectService = { setVisibility: async (id: string, visibility: ProjectType['visibility']) => { try { - await Engine.instance.api.service(projectPath).patch(id, { + await API.instance.service(projectPath).patch(id, { visibility }) } catch (err) { @@ -170,7 +170,7 @@ export const ProjectService = { setRepositoryPath: async (id: string, url: string) => { try { - await Engine.instance.api.service(projectPath).patch(id, { + await API.instance.service(projectPath).patch(id, { repositoryPath: url }) } catch (err) { @@ -181,7 +181,7 @@ export const ProjectService = { pushProject: async (id: string) => { try { - await Engine.instance.api.service(projectGithubPushPath).patch(id, {}) + await API.instance.service(projectGithubPushPath).patch(id, {}) } catch (err) { logger.error('Error with project push', err) throw err @@ -190,7 +190,7 @@ export const ProjectService = { createPermission: async (userInviteCode: InviteCode, projectId: string, type: string) => { try { - return Engine.instance.api.service(projectPermissionPath).create({ + return API.instance.service(projectPermissionPath).create({ inviteCode: userInviteCode, userId: '' as UserID, projectId: projectId, @@ -204,7 +204,7 @@ export const ProjectService = { patchPermission: async (id: string, type: string) => { try { - return Engine.instance.api.service(projectPermissionPath).patch(id, { + return API.instance.service(projectPermissionPath).patch(id, { type: type }) } catch (err) { @@ -215,7 +215,7 @@ export const ProjectService = { removePermission: async (id: string) => { try { - return Engine.instance.api.service(projectPermissionPath).remove(id) + return API.instance.service(projectPermissionPath).remove(id) } catch (err) { logger.error('Error with removing project-permission', err) throw err @@ -230,23 +230,23 @@ export const ProjectService = { useEffect(() => { // TODO #7254 - // Engine.instance.api.service(projectBuildPath).on('patched', (params) => {}) + // API.instance.service(projectBuildPath).on('patched', (params) => {}) const projectPatchedListener = (params) => { getMutableState(ProjectState).updateNeeded.set(true) } - Engine.instance.api.service(projectPath).on('patched', projectPatchedListener) + API.instance.service(projectPath).on('patched', projectPatchedListener) return () => { - Engine.instance.api.service(projectPath).off('patched', projectPatchedListener) + API.instance.service(projectPath).off('patched', projectPatchedListener) } }, []) }, fetchProjectBranches: async (url: string) => { try { - return (await Engine.instance.api.service(projectBranchesPath).get(url)).branches + return (await API.instance.service(projectBranchesPath).get(url)).branches } catch (err) { logger.error('Error with fetching tags for a project', err) throw err @@ -255,7 +255,7 @@ export const ProjectService = { fetchProjectCommits: async (url: string, branchName: string) => { try { - const projectCommits = await Engine.instance.api.service(projectCommitsPath).get(url, { + const projectCommits = await API.instance.service(projectCommitsPath).get(url, { query: { sourceBranch: branchName } @@ -270,7 +270,7 @@ export const ProjectService = { checkDestinationURLValid: async ({ url, inputProjectURL }: { url: string; inputProjectURL?: string }) => { try { - return Engine.instance.api.service(projectDestinationCheckPath).get(url, { + return API.instance.service(projectDestinationCheckPath).get(url, { query: { inputProjectURL } @@ -283,7 +283,7 @@ export const ProjectService = { checkUnfetchedCommit: async ({ url, selectedSHA }: { url: string; selectedSHA?: string }) => { try { - return Engine.instance.api.service(projectCheckUnfetchedCommitPath).get(url, { + return API.instance.service(projectCheckUnfetchedCommitPath).get(url, { query: { selectedSHA } @@ -306,7 +306,7 @@ export const ProjectService = { existingProject: boolean }) => { try { - return Engine.instance.api.service(projectCheckSourceDestinationMatchPath).find({ + return API.instance.service(projectCheckSourceDestinationMatchPath).find({ query: { sourceURL, selectedSHA, @@ -322,7 +322,7 @@ export const ProjectService = { updateEngine: async (tag: string, updateProjects: boolean, projectsToUpdate: ProjectBuildUpdateItemType[]) => { try { - await Engine.instance.api.service(projectBuildPath).patch(tag, { + await API.instance.service(projectBuildPath).patch(tag, { updateProjects, projectsToUpdate }) @@ -334,7 +334,7 @@ export const ProjectService = { fetchBuilderTags: async () => { try { - const result = await Engine.instance.api.service(projectBuilderTagsPath).find() + const result = await API.instance.service(projectBuilderTagsPath).find() getMutableState(ProjectState).builderTags.set(result) } catch (err) { logger.error('Error with getting builder tags', err) @@ -344,7 +344,7 @@ export const ProjectService = { getBuilderInfo: async () => { try { - const result = await Engine.instance.api.service(builderInfoPath).get() + const result = await API.instance.service(builderInfoPath).get() getMutableState(ProjectState).builderInfo.set(result) } catch (err) { logger.error('Error with getting engine info', err) @@ -355,7 +355,7 @@ export const ProjectService = { refreshGithubRepoAccess: async () => { try { getMutableState(ProjectState).refreshingGithubRepoAccess.set(true) - await Engine.instance.api.service(githubRepoAccessRefreshPath).find() + await API.instance.service(githubRepoAccessRefreshPath).find() getMutableState(ProjectState).refreshingGithubRepoAccess.set(false) await ProjectService.fetchProjects() } catch (err) { diff --git a/packages/client-core/src/common/services/RouterService.tsx b/packages/client-core/src/common/services/RouterService.tsx index 04418f88d5..ffe2b2ef8d 100644 --- a/packages/client-core/src/common/services/RouterService.tsx +++ b/packages/client-core/src/common/services/RouterService.tsx @@ -28,8 +28,8 @@ import i18n from 'i18next' import React, { lazy, useEffect, useLayoutEffect } from 'react' import { BrowserRouterProps as NativeBrowserRouterProps, Router, useSearchParams } from 'react-router-dom' +import { API } from '@etherealengine/common' import { routePath, RouteType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, NO_PROXY, startReactor, useHookstate } from '@etherealengine/hyperflux' import { loadRoute } from '@etherealengine/projects/loadRoute' @@ -139,9 +139,7 @@ export type CustomRoute = { * getCustomRoutes used to get the routes created by the user. */ export const getCustomRoutes = async (): Promise => { - const routes = (await Engine.instance.api - .service(routePath) - .find({ query: { paginate: false } })) as any as RouteType[] + const routes = (await API.instance.service(routePath).find({ query: { paginate: false } })) as any as RouteType[] const elements: CustomRoute[] = [] diff --git a/packages/client-core/src/social/services/ChannelService.ts b/packages/client-core/src/social/services/ChannelService.ts index 2cf2d742ee..ecba94c7a0 100755 --- a/packages/client-core/src/social/services/ChannelService.ts +++ b/packages/client-core/src/social/services/ChannelService.ts @@ -25,6 +25,7 @@ Ethereal Engine. All Rights Reserved. import { useEffect } from 'react' +import { API } from '@etherealengine/common' import { ChannelID, channelPath, @@ -64,7 +65,7 @@ export const ChannelState = defineState({ export const ChannelService = { getChannels: async () => { try { - const channelResult = (await Engine.instance.api + const channelResult = (await API.instance .service(channelPath) .find({ query: { paginate: false } })) as any as ChannelType[] const channelState = getMutableState(ChannelState) @@ -91,7 +92,7 @@ export const ChannelService = { }, getInstanceChannel: async (instanceID: InstanceID) => { try { - const channelResult = (await Engine.instance.api.service(channelPath).find({ + const channelResult = (await API.instance.service(channelPath).find({ query: { instanceId: instanceID, paginate: false @@ -132,7 +133,7 @@ export const ChannelService = { }, createChannel: async (users: UserID[]) => { try { - const channel = await Engine.instance.api.service(channelPath).create({ + const channel = await API.instance.service(channelPath).create({ users }) await ChannelService.getChannels() @@ -156,7 +157,7 @@ export const ChannelService = { }, removeUserFromChannel: async (channelId: ChannelID, userId: UserID) => { try { - await Engine.instance.api.service(channelUserPath).remove(null, { + await API.instance.service(channelUserPath).remove(null, { query: { channelId, userId @@ -170,7 +171,7 @@ export const ChannelService = { }, removeChannel: async (channelId: ChannelID) => { try { - await Engine.instance.api.service(channelPath).remove(channelId) + await API.instance.service(channelPath).remove(channelId) await ChannelService.getChannels() } catch (err) { NotificationService.dispatchNotify(err.message, { variant: 'error' }) @@ -224,16 +225,16 @@ export const ChannelService = { } } - Engine.instance.api.service(channelPath).on('created', channelCreatedListener) - Engine.instance.api.service(channelPath).on('patched', channelPatchedListener) - Engine.instance.api.service(channelPath).on('removed', channelRemovedListener) - Engine.instance.api.service(channelUserPath).on('removed', channelUserRemovedListener) + API.instance.service(channelPath).on('created', channelCreatedListener) + API.instance.service(channelPath).on('patched', channelPatchedListener) + API.instance.service(channelPath).on('removed', channelRemovedListener) + API.instance.service(channelUserPath).on('removed', channelUserRemovedListener) return () => { - Engine.instance.api.service(channelPath).off('created', channelCreatedListener) - Engine.instance.api.service(channelPath).off('patched', channelPatchedListener) - Engine.instance.api.service(channelPath).off('removed', channelRemovedListener) - Engine.instance.api.service(channelUserPath).off('removed', channelUserRemovedListener) + API.instance.service(channelPath).off('created', channelCreatedListener) + API.instance.service(channelPath).off('patched', channelPatchedListener) + API.instance.service(channelPath).off('removed', channelRemovedListener) + API.instance.service(channelUserPath).off('removed', channelUserRemovedListener) } }, []) } diff --git a/packages/client-core/src/social/services/FriendService.ts b/packages/client-core/src/social/services/FriendService.ts index 9e7934e9f4..c3288b852c 100644 --- a/packages/client-core/src/social/services/FriendService.ts +++ b/packages/client-core/src/social/services/FriendService.ts @@ -27,6 +27,7 @@ import { Paginated } from '@feathersjs/feathers' import i18n from 'i18next' import { useEffect } from 'react' +import { API } from '@etherealengine/common' import multiLogger from '@etherealengine/common/src/logger' import { UserID, @@ -34,7 +35,6 @@ import { userRelationshipPath, UserRelationshipType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, getState } from '@etherealengine/hyperflux' import { NotificationService } from '../../common/services/NotificationService' @@ -58,7 +58,7 @@ export const FriendService = { try { getMutableState(FriendState).isFetching.set(true) - const relationships = (await Engine.instance.api.service(userRelationshipPath).find({ + const relationships = (await API.instance.service(userRelationshipPath).find({ query: { userId, $limit: 100 @@ -75,7 +75,7 @@ export const FriendService = { }, acceptFriend: async (userId: UserID, relatedUserId: UserID) => { try { - await Engine.instance.api.service(userRelationshipPath).patch(relatedUserId, { + await API.instance.service(userRelationshipPath).patch(relatedUserId, { userRelationshipType: 'friend' }) @@ -129,14 +129,14 @@ export const FriendService = { FriendService.getUserRelationship(selfUser.id) } - Engine.instance.api.service(userRelationshipPath).on('created', userRelationshipCreatedListener) - Engine.instance.api.service(userRelationshipPath).on('patched', userRelationshipPatchedListener) - Engine.instance.api.service(userRelationshipPath).on('removed', userRelationshipRemovedListener) + API.instance.service(userRelationshipPath).on('created', userRelationshipCreatedListener) + API.instance.service(userRelationshipPath).on('patched', userRelationshipPatchedListener) + API.instance.service(userRelationshipPath).on('removed', userRelationshipRemovedListener) return () => { - Engine.instance.api.service(userRelationshipPath).off('created', userRelationshipCreatedListener) - Engine.instance.api.service(userRelationshipPath).off('patched', userRelationshipPatchedListener) - Engine.instance.api.service(userRelationshipPath).off('removed', userRelationshipRemovedListener) + API.instance.service(userRelationshipPath).off('created', userRelationshipCreatedListener) + API.instance.service(userRelationshipPath).off('patched', userRelationshipPatchedListener) + API.instance.service(userRelationshipPath).off('removed', userRelationshipRemovedListener) } }, []) } @@ -144,7 +144,7 @@ export const FriendService = { async function createRelation(userId: UserID, relatedUserId: UserID, type: 'requested' | 'blocking') { try { - await Engine.instance.api.service(userRelationshipPath).create({ + await API.instance.service(userRelationshipPath).create({ relatedUserId, userRelationshipType: type, userId: '' as UserID @@ -158,7 +158,7 @@ async function createRelation(userId: UserID, relatedUserId: UserID, type: 'requ async function removeRelation(userId: UserID, relatedUserId: UserID) { try { - await Engine.instance.api.service(userRelationshipPath).remove(relatedUserId) + await API.instance.service(userRelationshipPath).remove(relatedUserId) FriendService.getUserRelationship(userId) } catch (err) { diff --git a/packages/client-core/src/social/services/InviteService.ts b/packages/client-core/src/social/services/InviteService.ts index b71085fcf8..e0beeea349 100644 --- a/packages/client-core/src/social/services/InviteService.ts +++ b/packages/client-core/src/social/services/InviteService.ts @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import { Paginated } from '@feathersjs/feathers' import { useEffect } from 'react' +import { API } from '@etherealengine/common' import { EMAIL_REGEX, INVITE_CODE_REGEX, PHONE_REGEX, USER_ID_REGEX } from '@etherealengine/common/src/regex' import { InviteCode, @@ -35,7 +36,6 @@ import { inviteCodeLookupPath, invitePath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, getState } from '@etherealengine/hyperflux' import { NotificationService } from '../../common/services/NotificationService' @@ -112,7 +112,7 @@ export const InviteService = { return } else { try { - const inviteCodeLookups = await Engine.instance.api.service(inviteCodeLookupPath).find({ + const inviteCodeLookups = await API.instance.service(inviteCodeLookupPath).find({ query: { inviteCode: inviteCode } @@ -144,12 +144,12 @@ export const InviteService = { } try { - const existingInviteResult = (await Engine.instance.api.service(invitePath).find({ + const existingInviteResult = (await API.instance.service(invitePath).find({ query: { ...data, action: 'sent' } })) as Paginated let inviteResult - if (existingInviteResult.total === 0) inviteResult = await Engine.instance.api.service(invitePath).create(data) + if (existingInviteResult.total === 0) inviteResult = await API.instance.service(invitePath).create(data) NotificationService.dispatchNotify('Invite Sent', { variant: 'success' }) getMutableState(InviteState).sentUpdateNeeded.set(true) @@ -180,7 +180,7 @@ export const InviteService = { } try { - const inviteResult = (await Engine.instance.api.service(invitePath).find({ + const inviteResult = (await API.instance.service(invitePath).find({ query: { $sort: sortData, action: 'received', @@ -225,7 +225,7 @@ export const InviteService = { } } try { - const inviteResult = (await Engine.instance.api.service(invitePath).find({ + const inviteResult = (await API.instance.service(invitePath).find({ query: { $sort: sortData, action: 'sent', @@ -250,7 +250,7 @@ export const InviteService = { }, removeInvite: async (inviteId: string) => { try { - await Engine.instance.api.service(invitePath).remove(inviteId) + await API.instance.service(invitePath).remove(inviteId) getMutableState(InviteState).sentUpdateNeeded.set(true) } catch (err) { NotificationService.dispatchNotify(err.message, { variant: 'error' }) @@ -258,7 +258,7 @@ export const InviteService = { }, acceptInvite: async (invite: InviteType) => { try { - await Engine.instance.api.service(acceptInvitePath).get(invite.id, { + await API.instance.service(acceptInvitePath).get(invite.id, { query: { passcode: invite.passcode } @@ -270,7 +270,7 @@ export const InviteService = { }, declineInvite: async (invite: InviteType) => { try { - await Engine.instance.api.service(invitePath).remove(invite.id) + await API.instance.service(invitePath).remove(invite.id) getMutableState(InviteState).receivedUpdateNeeded.set(true) } catch (err) { NotificationService.dispatchNotify(err.message, { variant: 'error' }) @@ -304,12 +304,12 @@ export const InviteService = { } } - Engine.instance.api.service(invitePath).on('created', inviteCreatedListener) - Engine.instance.api.service(invitePath).on('removed', inviteRemovedListener) + API.instance.service(invitePath).on('created', inviteCreatedListener) + API.instance.service(invitePath).on('removed', inviteRemovedListener) return () => { - Engine.instance.api.service(invitePath).off('created', inviteCreatedListener) - Engine.instance.api.service(invitePath).off('removed', inviteRemovedListener) + API.instance.service(invitePath).off('created', inviteCreatedListener) + API.instance.service(invitePath).off('removed', inviteRemovedListener) } }, []) } diff --git a/packages/client-core/src/social/services/LocationService.ts b/packages/client-core/src/social/services/LocationService.ts index 689fd5c084..0846d553a3 100755 --- a/packages/client-core/src/social/services/LocationService.ts +++ b/packages/client-core/src/social/services/LocationService.ts @@ -36,8 +36,8 @@ import { import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, getState } from '@etherealengine/hyperflux' +import { API } from '@etherealengine/common' import { useEffect } from 'react' -import { API } from '../../API' import { NotificationService } from '../../common/services/NotificationService' import { AuthState } from '../../user/services/AuthService' @@ -141,7 +141,7 @@ export const LocationService = { getLocation: async (locationId: LocationID) => { try { LocationState.fetchingCurrentSocialLocation() - const location = await API.instance.client.service(locationPath).get(locationId) + const location = await API.instance.service(locationPath).get(locationId) LocationState.socialLocationRetrieved(location) } catch (err) { NotificationService.dispatchNotify(err.message, { variant: 'error' }) @@ -149,7 +149,7 @@ export const LocationService = { }, getLocationByName: async (locationName: string) => { LocationState.fetchingCurrentSocialLocation() - const locationResult = (await API.instance.client.service(locationPath).find({ + const locationResult = (await API.instance.service(locationPath).find({ query: { slugifiedName: locationName } @@ -167,7 +167,7 @@ export const LocationService = { } }, getLobby: async () => { - const lobbyResult = (await API.instance.client.service(locationPath).find({ + const lobbyResult = (await API.instance.service(locationPath).find({ query: { isLobby: true, $limit: 1 @@ -182,7 +182,7 @@ export const LocationService = { }, banUserFromLocation: async (userId: UserID, locationId: LocationID) => { try { - await API.instance.client.service(locationBanPath).create({ + await API.instance.service(locationBanPath).create({ userId: userId, locationId: locationId }) @@ -198,13 +198,13 @@ export const LocationService = { const locationBan = params.locationBan if (selfUser.id === locationBan.userId && currentLocation.id === locationBan.locationId) { const userId = selfUser.id ?? '' - const user = await Engine.instance.api.service(userPath).get(userId) + const user = await API.instance.service(userPath).get(userId) getMutableState(AuthState).merge({ user }) } } - Engine.instance.api.service(locationBanPath).on('created', locationBanCreatedListener) + API.instance.service(locationBanPath).on('created', locationBanCreatedListener) return () => { - Engine.instance.api.service(locationBanPath).off('created', locationBanCreatedListener) + API.instance.service(locationBanPath).off('created', locationBanCreatedListener) } }, []) } diff --git a/packages/client-core/src/user/components/UserMenu/menus/ProfileMenu.tsx b/packages/client-core/src/user/components/UserMenu/menus/ProfileMenu.tsx index b0f78dad6c..546a1a00e3 100755 --- a/packages/client-core/src/user/components/UserMenu/menus/ProfileMenu.tsx +++ b/packages/client-core/src/user/components/UserMenu/menus/ProfileMenu.tsx @@ -58,7 +58,6 @@ import FormControlLabel from '@etherealengine/ui/src/primitives/mui/FormControlL import Icon from '@etherealengine/ui/src/primitives/mui/Icon' import IconButton from '@etherealengine/ui/src/primitives/mui/IconButton' -import { Engine } from '@etherealengine/ecs' import Grid from '@etherealengine/ui/src/primitives/mui/Grid' import { initialAuthState, initialOAuthConnectedState } from '../../../../common/initialAuthState' import { NotificationService } from '../../../../common/services/NotificationService' @@ -117,7 +116,7 @@ const ProfileMenu = ({ hideLogin, onClose, isPopover }: Props): JSX.Element => { useEffect(() => { if (!originallyAcceptedTOS.value && checked18OrOver.value) { - Engine.instance.api + API.instance .service(userPath) .patch(userId, { acceptedTOS: true }) .then(() => { diff --git a/packages/client-core/src/user/services/AuthService.ts b/packages/client-core/src/user/services/AuthService.ts index 0ea9010f87..08dd8a02d3 100755 --- a/packages/client-core/src/user/services/AuthService.ts +++ b/packages/client-core/src/user/services/AuthService.ts @@ -29,6 +29,7 @@ import i18n from 'i18next' import { useEffect } from 'react' import { v4 as uuidv4 } from 'uuid' +import { API } from '@etherealengine/common/src/API' import config, { validateEmail, validatePhoneNumber } from '@etherealengine/common/src/config' import { AuthUserSeed, resolveAuthUser } from '@etherealengine/common/src/interfaces/AuthUser' import multiLogger from '@etherealengine/common/src/logger' @@ -57,15 +58,14 @@ import { userPath, userSettingPath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { + HyperFlux, defineState, getMutableState, getState, syncStateWithLocalStorage, useHookstate } from '@etherealengine/hyperflux' -import { API } from '../../API' import { NotificationService } from '../../common/services/NotificationService' export const logger = multiLogger.child({ component: 'client-core:AuthService' }) @@ -170,16 +170,16 @@ export interface LinkedInLoginForm { */ async function _resetToGuestToken(options = { reset: true }) { if (options.reset) { - await API.instance.client.authentication.reset() + await API.instance.authentication.reset() } - const newProvider = await Engine.instance.api.service(identityProviderPath).create({ + const newProvider = await API.instance.service(identityProviderPath).create({ type: 'guest', token: uuidv4(), userId: '' as UserID }) const accessToken = newProvider.accessToken! console.log(`Created new guest accessToken: ${accessToken}`) - await API.instance.client.authentication.setAccessToken(accessToken as string) + await API.instance.authentication.setAccessToken(accessToken as string) return accessToken } @@ -195,22 +195,22 @@ export const AuthService = { const accessToken = !forceClientAuthReset && authState?.authUser?.accessToken?.value if (forceClientAuthReset) { - await API.instance.client.authentication.reset() + await API.instance.authentication.reset() } if (accessToken) { - await API.instance.client.authentication.setAccessToken(accessToken as string) + await API.instance.authentication.setAccessToken(accessToken as string) } else { await _resetToGuestToken({ reset: false }) } let res: AuthenticationResult try { - res = await API.instance.client.reAuthenticate() + res = await API.instance.reAuthenticate() } catch (err) { if (err.className === 'not-found' || (err.className === 'not-authenticated' && err.message === 'jwt expired')) { authState.merge({ isLoggedIn: false, user: UserSeed, authUser: AuthUserSeed }) await _resetToGuestToken() - res = await API.instance.client.reAuthenticate() + res = await API.instance.reAuthenticate() } else { logger.error(err, 'Error re-authenticating') throw err @@ -222,7 +222,7 @@ export const AuthService = { if (!identityProvider?.id) { authState.merge({ isLoggedIn: false, user: UserSeed, authUser: AuthUserSeed }) await _resetToGuestToken() - res = await API.instance.client.reAuthenticate() + res = await API.instance.reAuthenticate() } const authUser = resolveAuthUser(res) // authUser is now { accessToken, authentication, identityProvider } @@ -243,7 +243,7 @@ export const AuthService = { async loadUserData(userId: UserID) { try { - const client = API.instance.client + const client = API.instance const user = await client.service(userPath).get(userId) if (!user.userSetting) { const settingsRes = (await client @@ -278,7 +278,7 @@ export const AuthService = { authState.merge({ isProcessing: true, error: '' }) try { - const authenticationResult = await API.instance.client.authenticate({ + const authenticationResult = await API.instance.authenticate({ strategy: 'local', email: form.email, password: form.password @@ -378,24 +378,24 @@ export const AuthService = { }, async removeUserOAuth(service: string) { - const ipResult = (await Engine.instance.api.service(identityProviderPath).find()) as Paginated + const ipResult = (await API.instance.service(identityProviderPath).find()) as Paginated const ipToRemove = ipResult.data.find((ip) => ip.type === service) if (ipToRemove) { if (ipResult.total === 1) { NotificationService.dispatchNotify('You can not remove your last login method.', { variant: 'warning' }) } else { const otherIp = ipResult.data.find((ip) => ip.type !== service) - const newTokenResult = await Engine.instance.api.service(generateTokenPath).create({ + const newTokenResult = await API.instance.service(generateTokenPath).create({ type: otherIp!.type, token: otherIp!.token }) if (newTokenResult?.token) { getMutableState(AuthState).merge({ isProcessing: true, error: '' }) - await API.instance.client.authentication.setAccessToken(newTokenResult.token) - const res = await API.instance.client.reAuthenticate(true) + await API.instance.authentication.setAccessToken(newTokenResult.token) + const res = await API.instance.reAuthenticate(true) const authUser = resolveAuthUser(res) - await Engine.instance.api.service(identityProviderPath).remove(ipToRemove.id) + await API.instance.service(identityProviderPath).remove(ipToRemove.id) const authState = getMutableState(AuthState) authState.merge({ authUser }) await AuthService.loadUserData(authUser.identityProvider.userId) @@ -409,8 +409,8 @@ export const AuthService = { const authState = getMutableState(AuthState) authState.merge({ isProcessing: true, error: '' }) try { - await API.instance.client.authentication.setAccessToken(accessToken as string) - const res = await API.instance.client.authenticate({ + await API.instance.authentication.setAccessToken(accessToken as string) + const res = await API.instance.authenticate({ strategy: 'jwt', accessToken }) @@ -446,7 +446,7 @@ export const AuthService = { async loginUserMagicLink(token, redirectSuccess, redirectError) { try { - const res = await Engine.instance.api.service(loginPath).get(token) + const res = await API.instance.service(loginPath).get(token) await AuthService.loginUserByJwt(res.token!, '/', '/') } catch (err) { NotificationService.dispatchNotify(err.message, { variant: 'error' }) @@ -459,7 +459,7 @@ export const AuthService = { const authState = getMutableState(AuthState) authState.merge({ isProcessing: true, error: '' }) try { - await API.instance.client.logout() + await API.instance.logout() authState.merge({ isLoggedIn: false, user: UserSeed, authUser: AuthUserSeed }) } catch (_) { authState.merge({ isLoggedIn: false, user: UserSeed, authUser: AuthUserSeed }) @@ -473,7 +473,7 @@ export const AuthService = { const authState = getMutableState(AuthState) authState.merge({ isProcessing: true, error: '' }) try { - const identityProvider: any = await Engine.instance.api.service(identityProviderPath).create({ + const identityProvider: any = await API.instance.service(identityProviderPath).create({ token: form.email, type: 'password', userId: '' as UserID @@ -548,7 +548,7 @@ export const AuthService = { } try { - await Engine.instance.api + await API.instance .service(magicLinkPath) .create({ type, [paramName]: emailPhone, accessToken: storedToken, redirectUrl }) const message = { @@ -572,7 +572,7 @@ export const AuthService = { authState.merge({ isProcessing: true, error: '' }) try { - const identityProvider = await Engine.instance.api.service(identityProviderPath).create({ + const identityProvider = await API.instance.service(identityProviderPath).create({ token: form.email, type: 'password', userId: '' as UserID @@ -590,7 +590,7 @@ export const AuthService = { const authState = getMutableState(AuthState) authState.merge({ isProcessing: true, error: '' }) try { - const identityProvider = (await Engine.instance.api.service(magicLinkPath).create({ + const identityProvider = (await API.instance.service(magicLinkPath).create({ email, type: 'email', userId @@ -618,7 +618,7 @@ export const AuthService = { } try { - const identityProvider = (await Engine.instance.api.service(magicLinkPath).create({ + const identityProvider = (await API.instance.service(magicLinkPath).create({ mobile: sendPhone, type: 'sms', userId @@ -644,7 +644,7 @@ export const AuthService = { async removeConnection(identityProviderId: number, userId: UserID) { getMutableState(AuthState).merge({ isProcessing: true, error: '' }) try { - await Engine.instance.api.service(identityProviderPath).remove(identityProviderId) + await API.instance.service(identityProviderPath).remove(identityProviderId) return AuthService.loadUserData(userId) } catch (err) { NotificationService.dispatchNotify(err.message, { variant: 'error' }) @@ -658,30 +658,30 @@ export const AuthService = { }, async updateUserSettings(id: UserSettingID, data: UserSettingPatch) { - const response = await Engine.instance.api.service(userSettingPath).patch(id, data) + const response = await API.instance.service(userSettingPath).patch(id, data) getMutableState(AuthState).user.userSetting.merge(response) }, async removeUser(userId: UserID) { - await Engine.instance.api.service(userPath).remove(userId) + await API.instance.service(userPath).remove(userId) AuthService.logoutUser() }, async updateApiKey() { - const userApiKey = (await Engine.instance.api.service(userApiKeyPath).find()) as Paginated + const userApiKey = (await API.instance.service(userApiKeyPath).find()) as Paginated let apiKey: UserApiKeyType | undefined if (userApiKey.data.length > 0) { - apiKey = await Engine.instance.api.service(userApiKeyPath).patch(userApiKey.data[0].id, {}) + apiKey = await API.instance.service(userApiKeyPath).patch(userApiKey.data[0].id, {}) } else { - apiKey = await Engine.instance.api.service(userApiKeyPath).create({}) + apiKey = await API.instance.service(userApiKeyPath).create({}) } getMutableState(AuthState).user.merge({ apiKey }) }, async createLoginToken() { - return Engine.instance.api.service(loginTokenPath).create({}) + return API.instance.service(loginTokenPath).create({}) }, useAPIListeners: () => { @@ -706,17 +706,17 @@ export const AuthService = { const selfUser = getMutableState(AuthState).user if (selfUser.id.value === userAvatar.userId) { - const user = await Engine.instance.api.service(userPath).get(userAvatar.userId) + const user = await API.instance.service(userPath).get(userAvatar.userId) getMutableState(AuthState).user.merge(user) } } - Engine.instance.api.service(userPath).on('patched', userPatchedListener) - Engine.instance.api.service(userAvatarPath).on('patched', userAvatarPatchedListener) + API.instance.service(userPath).on('patched', userPatchedListener) + API.instance.service(userAvatarPath).on('patched', userAvatarPatchedListener) return () => { - Engine.instance.api.service(userPath).off('patched', userPatchedListener) - Engine.instance.api.service(userAvatarPath).off('patched', userAvatarPatchedListener) + API.instance.service(userPath).off('patched', userPatchedListener) + API.instance.service(userAvatarPath).off('patched', userAvatarPatchedListener) } }, []) } @@ -772,7 +772,7 @@ export const useAuthenticated = () => { }, []) useEffect(() => { - Engine.instance.userID = authState.user.id.value + HyperFlux.store.userID = authState.user.id.value }, [authState.user.id]) return authState.isLoggedIn.value diff --git a/packages/client-core/src/user/services/AvatarService.ts b/packages/client-core/src/user/services/AvatarService.ts index 5d9f2ce350..c1c7a5f482 100644 --- a/packages/client-core/src/user/services/AvatarService.ts +++ b/packages/client-core/src/user/services/AvatarService.ts @@ -25,6 +25,7 @@ Ethereal Engine. All Rights Reserved. import { Paginated } from '@feathersjs/feathers' +import { API } from '@etherealengine/common' import { AvatarID, avatarPath, @@ -62,7 +63,7 @@ export const AvatarState = defineState({ export const AvatarService = { async createAvatar(model: File, thumbnail: File, avatarName: string, isPublic: boolean) { - const newAvatar = await Engine.instance.api.service(avatarPath).create({ + const newAvatar = await API.instance.service(avatarPath).create({ name: avatarName, isPublic }) @@ -79,7 +80,7 @@ export const AvatarService = { const skip = avatarState.skip.value const newSkip = incDec === 'increment' ? skip + AVATAR_PAGE_LIMIT : incDec === 'decrement' ? skip - AVATAR_PAGE_LIMIT : skip - const result = (await Engine.instance.api.service(avatarPath).find({ + const result = (await API.instance.service(avatarPath).find({ query: { name: { $like: `%${search}%` @@ -133,7 +134,7 @@ export const AvatarService = { } } - const avatar = await Engine.instance.api.service(avatarPath).patch(originalAvatar.id, payload) + const avatar = await API.instance.service(avatarPath).patch(originalAvatar.id, payload) getMutableState(AvatarState).avatarList.set((prevAvatarList) => { const index = prevAvatarList.findIndex((item) => item.id === avatar.id) prevAvatarList[index] = avatar @@ -147,7 +148,7 @@ export const AvatarService = { }, async removeStaticResource(id: string) { - return Engine.instance.api.service(staticResourcePath).remove(id) + return API.instance.service(staticResourcePath).remove(id) }, async uploadAvatarModel(avatar: File, thumbnail: File, avatarName: string, isPublic: boolean, avatarId?: AvatarID) { @@ -163,16 +164,14 @@ export const AvatarService = { async getAvatar(id: AvatarID) { try { - return Engine.instance.api.service(avatarPath).get(id) + return API.instance.service(avatarPath).get(id) } catch (err) { return null } }, async updateUsername(userId: UserID, name: UserName) { - const { name: updatedName } = (await Engine.instance.api - .service(userPath) - .patch(userId, { name: name })) as UserType + const { name: updatedName } = (await API.instance.service(userPath).patch(userId, { name: name })) as UserType NotificationService.dispatchNotify(i18n.t('user:usermenu.profile.update-msg').toString(), { variant: 'success' }) getMutableState(AuthState).user.merge({ name: updatedName }) dispatchAction(AvatarNetworkAction.setName({ entityUUID: (userId + '_avatar') as EntityUUID, name: updatedName })) diff --git a/packages/client-core/src/util/wait-for-client-authenticated.ts b/packages/client-core/src/util/wait-for-client-authenticated.ts index b52082e8dc..2c40b2e2ce 100644 --- a/packages/client-core/src/util/wait-for-client-authenticated.ts +++ b/packages/client-core/src/util/wait-for-client-authenticated.ts @@ -23,12 +23,10 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ -import { Engine } from '@etherealengine/ecs/src/Engine' - -import { FeathersClient } from '../API' +import { API } from '@etherealengine/common' async function waitForClientAuthenticated(): Promise { - const api = Engine.instance.api as FeathersClient + const api = API.instance // as FeathersClient console.log('Client authenticated?', api.authentication?.authenticated) if (api.authentication?.authenticated === true) return else diff --git a/packages/client/src/engine.tsx b/packages/client/src/engine.tsx index 55fa0fe087..ed06551edc 100755 --- a/packages/client/src/engine.tsx +++ b/packages/client/src/engine.tsx @@ -23,63 +23,13 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ -import React, { Suspense, useEffect } from 'react' -import { useTranslation } from 'react-i18next' - -import { API } from '@etherealengine/client-core/src/API' -import { BrowserRouter, history } from '@etherealengine/client-core/src/common/services/RouterService' -import waitForClientAuthenticated from '@etherealengine/client-core/src/util/wait-for-client-authenticated' -import { pipeLogs } from '@etherealengine/common/src/logger' -import { Engine, createEngine } from '@etherealengine/ecs/src/Engine' -import { getMutableState } from '@etherealengine/hyperflux' -import { EngineState } from '@etherealengine/spatial/src/EngineState' +import { createEngine } from '@etherealengine/ecs/src/Engine' import { startTimer } from '@etherealengine/spatial/src/startTimer' - -import MetaTags from '@etherealengine/client-core/src/common/components/MetaTags' -import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' -import { initializei18n } from './util' - -const initializeLogs = async () => { - await waitForClientAuthenticated() - pipeLogs(Engine.instance.api) -} +import React from 'react' createEngine() startTimer() -getMutableState(EngineState).publicPath.set( - // @ts-ignore - import.meta.env.BASE_URL === '/client/' ? location.origin : import.meta.env.BASE_URL!.slice(0, -1) // remove trailing '/' -) -initializei18n() -API.createAPI() -initializeLogs() - -export default function ({ children }): JSX.Element { - const { t } = useTranslation() - - useEffect(() => { - const urlSearchParams = new URLSearchParams(window.location.search) - const redirectUrl = urlSearchParams.get('redirectUrl') - if (redirectUrl) { - history.push(redirectUrl) - } - }, []) - return ( - <> - - - - - } - > - {children} - - - - ) +export default function ({ children }: { children: React.ReactNode }) { + return <>{children} } diff --git a/packages/client/src/main.tsx b/packages/client/src/main.tsx index 7e49460e6f..dae5e55aa4 100755 --- a/packages/client/src/main.tsx +++ b/packages/client/src/main.tsx @@ -39,7 +39,7 @@ const $offline = lazy(() => import('@etherealengine/client/src/pages/offline/off const $location = lazy(() => import('@etherealengine/client/src/pages/location/location')) const $auth = lazy(() => import('@etherealengine/client/src/pages/auth/authRoutes')) -const Engine = lazy(() => import('./engine')) +const Store = lazy(() => import('./store')) const AppPage = lazy(() => import('./pages/AppPage')) const Router = lazy(() => import('./route/CustomRouter')) @@ -47,7 +47,7 @@ const Router = lazy(() => import('./route/CustomRouter')) const App = () => { return ( - + {/* @todo - these are for backwards compatibility with non tailwind pages - they will be removed eventually */} { } /> - + ) } diff --git a/packages/client/src/pages/AppPage.tsx b/packages/client/src/pages/AppPage.tsx index bb138805cd..da0bafe505 100755 --- a/packages/client/src/pages/AppPage.tsx +++ b/packages/client/src/pages/AppPage.tsx @@ -32,7 +32,6 @@ import { initGA, logPageView } from '@etherealengine/client-core/src/common/anal import { NotificationSnackbar } from '@etherealengine/client-core/src/common/services/NotificationService' import { useSearchParamState } from '@etherealengine/client-core/src/common/services/RouterService' import { useThemeProvider } from '@etherealengine/client-core/src/common/services/ThemeService' -import Debug from '@etherealengine/client-core/src/components/Debug' import InviteToast from '@etherealengine/client-core/src/components/InviteToast' import { LoadWebappInjection } from '@etherealengine/client-core/src/components/LoadWebappInjection' import { useAuthenticated } from '@etherealengine/client-core/src/user/services/AuthService' @@ -63,7 +62,6 @@ const AppPage = (props: { children: React.ReactNode }) => { {props.children} - ) } diff --git a/packages/client/src/pages/admin/index.tsx b/packages/client/src/pages/admin/index.tsx index 18f77949a7..71020d8ad8 100644 --- a/packages/client/src/pages/admin/index.tsx +++ b/packages/client/src/pages/admin/index.tsx @@ -26,7 +26,10 @@ Ethereal Engine. All Rights Reserved. import { t } from 'i18next' import React, { Suspense } from 'react' +import '../../engine' + import AdminRoutes from '@etherealengine/client-core/src/admin/adminRoutes' +import Debug from '@etherealengine/client-core/src/components/Debug' import { useEngineInjection } from '@etherealengine/client-core/src/components/World/EngineHooks' import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' @@ -37,11 +40,14 @@ const LocationRoutes = () => { return return ( - } - > - - + <> + } + > + + + + ) } diff --git a/packages/client/src/pages/capture/capture.tsx b/packages/client/src/pages/capture/capture.tsx index 8d9d081335..9cabeb1f78 100755 --- a/packages/client/src/pages/capture/capture.tsx +++ b/packages/client/src/pages/capture/capture.tsx @@ -26,6 +26,8 @@ Ethereal Engine. All Rights Reserved. import React, { useEffect } from 'react' import { useParams } from 'react-router-dom' +import '../../engine' + import { NotificationService } from '@etherealengine/client-core/src/common/services/NotificationService' import { useNetwork } from '@etherealengine/client-core/src/components/World/EngineHooks' import { LocationService, LocationState } from '@etherealengine/client-core/src/social/services/LocationService' @@ -42,6 +44,7 @@ import { getMutableComponent, hasComponent, useQuery } from '@etherealengine/ecs import '@etherealengine/engine/src/EngineModule' +import Debug from '@etherealengine/client-core/src/components/Debug' import { AvatarControllerComponent } from '@etherealengine/engine/src/avatar/components/AvatarControllerComponent' import { RigidBodyComponent } from '@etherealengine/spatial/src/physics/components/RigidBodyComponent' @@ -84,7 +87,12 @@ export const CaptureLocation = () => { AuthService.useAPIListeners() - return + return ( + <> + + + + ) } export default CaptureLocation diff --git a/packages/client/src/pages/chat/chat.tsx b/packages/client/src/pages/chat/chat.tsx index aa73977896..666cbcd625 100644 --- a/packages/client/src/pages/chat/chat.tsx +++ b/packages/client/src/pages/chat/chat.tsx @@ -27,17 +27,23 @@ import { t } from 'i18next' import React, { Suspense } from 'react' import { Route, Routes } from 'react-router-dom' +import '../../engine' + +import Debug from '@etherealengine/client-core/src/components/Debug' import { ChatPage } from '@etherealengine/ui/src/pages/Chat/chat' import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' export default function Chat() { return ( - } - > - - } /> - - + <> + } + > + + } /> + + + + ) } diff --git a/packages/client/src/pages/editor/index.tsx b/packages/client/src/pages/editor/index.tsx index 7999701a3c..a23c0a14ad 100644 --- a/packages/client/src/pages/editor/index.tsx +++ b/packages/client/src/pages/editor/index.tsx @@ -26,14 +26,16 @@ Ethereal Engine. All Rights Reserved. import { t } from 'i18next' import React, { Suspense, useEffect } from 'react' -import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' +import '../../engine' import { RouterState } from '@etherealengine/client-core/src/common/services/RouterService' +import Debug from '@etherealengine/client-core/src/components/Debug' import { PopupMenuInline } from '@etherealengine/client-core/src/user/components/UserMenu/PopupMenuInline' import { AuthState } from '@etherealengine/client-core/src/user/services/AuthService' import { userHasAccess } from '@etherealengine/client-core/src/user/userHasAccess' import { EditorPage, useStudioEditor } from '@etherealengine/editor/src/pages/EditorPage' import { getMutableState, useHookstate } from '@etherealengine/hyperflux' +import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' import { Route, Routes, useLocation } from 'react-router-dom' export const EditorRouter = () => { @@ -71,7 +73,12 @@ const EditorProtectedRoutes = () => { if (!isAuthorized.value) return - return + return ( + <> + + + + ) } export default EditorProtectedRoutes diff --git a/packages/client/src/pages/index.tsx b/packages/client/src/pages/index.tsx index f19d217e74..7f11f4f242 100755 --- a/packages/client/src/pages/index.tsx +++ b/packages/client/src/pages/index.tsx @@ -30,8 +30,6 @@ import { Navigate } from 'react-router-dom' import styles from '@etherealengine/client-core/src/admin/old-styles/admin.module.scss' import { NotificationService } from '@etherealengine/client-core/src/common/services/NotificationService' -import '@etherealengine/client-core/src/user/UserUISystem' - import { PopupMenuState } from '@etherealengine/client-core/src/user/components/UserMenu/PopupMenuService' import config from '@etherealengine/common/src/config' import { getState, useMutableState } from '@etherealengine/hyperflux' diff --git a/packages/client/src/pages/location/location.tsx b/packages/client/src/pages/location/location.tsx index d815029436..0ca145420e 100644 --- a/packages/client/src/pages/location/location.tsx +++ b/packages/client/src/pages/location/location.tsx @@ -27,6 +27,8 @@ import { t } from 'i18next' import React, { Suspense, useRef } from 'react' import { Route, Routes } from 'react-router-dom' +import '../../engine' + import { useEngineInjection } from '@etherealengine/client-core/src/components/World/EngineHooks' import { useEngineCanvas } from '@etherealengine/client-core/src/hooks/useEngineCanvas' import LocationPage from '@etherealengine/client-core/src/world/Location' diff --git a/packages/client/src/store.tsx b/packages/client/src/store.tsx new file mode 100755 index 0000000000..783bd604da --- /dev/null +++ b/packages/client/src/store.tsx @@ -0,0 +1,79 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + +import React, { Suspense, useEffect } from 'react' +import { useTranslation } from 'react-i18next' + +import { API } from '@etherealengine/client-core/src/API' +import { BrowserRouter, history } from '@etherealengine/client-core/src/common/services/RouterService' +import waitForClientAuthenticated from '@etherealengine/client-core/src/util/wait-for-client-authenticated' +import { API as CommonAPI } from '@etherealengine/common' +import { pipeLogs } from '@etherealengine/common/src/logger' +import { createHyperStore } from '@etherealengine/hyperflux' + +import MetaTags from '@etherealengine/client-core/src/common/components/MetaTags' +import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' +import { initializei18n } from './util' + +const initializeLogs = async () => { + await waitForClientAuthenticated() + pipeLogs(CommonAPI.instance) +} + +const publicPath = import.meta.env.BASE_URL === '/client/' ? location.origin : import.meta.env.BASE_URL!.slice(0, -1) // remove trailing '/' +createHyperStore({ publicPath }) +initializei18n() +API.createAPI() +initializeLogs() + +export default function ({ children }): JSX.Element { + const { t } = useTranslation() + + useEffect(() => { + const urlSearchParams = new URLSearchParams(window.location.search) + const redirectUrl = urlSearchParams.get('redirectUrl') + if (redirectUrl) { + history.push(redirectUrl) + } + }, []) + + return ( + <> + + + + + } + > + {children} + + + + ) +} diff --git a/packages/common/index.ts b/packages/common/index.ts new file mode 100644 index 0000000000..7038406043 --- /dev/null +++ b/packages/common/index.ts @@ -0,0 +1 @@ +export { API } from './src/API' diff --git a/packages/common/src/API.ts b/packages/common/src/API.ts new file mode 100644 index 0000000000..75af45e43b --- /dev/null +++ b/packages/common/src/API.ts @@ -0,0 +1,6 @@ +import { FeathersApplication } from '@feathersjs/feathers' +import { ServiceTypes } from '../declarations' + +export const API = { + instance: null! as FeathersApplication +} diff --git a/packages/ecs/src/Engine.ts b/packages/ecs/src/Engine.ts index 3a8464df67..2ee9d27369 100755 --- a/packages/ecs/src/Engine.ts +++ b/packages/ecs/src/Engine.ts @@ -23,15 +23,13 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ -import type { FeathersApplication } from '@feathersjs/feathers' import * as bitECS from 'bitecs' import { getAllEntities } from 'bitecs' import { Cache } from 'three' -import type { ServiceTypes } from '@etherealengine/common/declarations' -import type { UserID } from '@etherealengine/common/src/schema.type.module' +import { API } from '@etherealengine/common' import * as Hyperflux from '@etherealengine/hyperflux' -import { createHyperStore, getState, NO_PROXY_STEALTH, ReactorReconciler } from '@etherealengine/hyperflux' +import { getState, NO_PROXY_STEALTH, ReactorReconciler } from '@etherealengine/hyperflux' import { disposeStore, HyperFlux, HyperStore } from '@etherealengine/hyperflux/functions/StoreFunctions' import { ECSState } from './ECSState' @@ -43,10 +41,13 @@ import { SystemState } from './SystemState' export class Engine { static instance: Engine - api: FeathersApplication - - /** The uuid of the logged-in user */ - userID: UserID + /** + * @deprecated use "Engine.instance.store.userID" instead + * The uuid of the logged-in user + */ + get userID() { + return Engine.instance.store.userID + } store: HyperStore @@ -86,14 +87,12 @@ globalThis.Hyperflux = Hyperflux export function createEngine() { if (Engine.instance) throw new Error('Store already exists') Engine.instance = new Engine() - Engine.instance.store = bitECS.createWorld( - createHyperStore({ - getDispatchTime: () => getState(ECSState).simulationTime, - getCurrentReactorRoot: () => - getState(SystemState).activeSystemReactors.get(getState(SystemState).currentSystemUUID) - }) - ) as HyperStore - const UndefinedEntity = bitECS.addEntity(HyperFlux.store) + const hyperstore = HyperFlux.store + hyperstore.getCurrentReactorRoot = () => + getState(SystemState).activeSystemReactors.get(getState(SystemState).currentSystemUUID) + hyperstore.getDispatchTime = () => getState(ECSState).simulationTime + Engine.instance.store = bitECS.createWorld(hyperstore) as HyperStore + const UndefinedEntity = bitECS.addEntity(hyperstore) } export async function destroyEngine() { @@ -101,10 +100,10 @@ export async function destroyEngine() { getState(ECSState).timer?.clear() - if (Engine.instance.api) { - if ((Engine.instance.api as any).server) await Engine.instance.api.teardown() + if (API.instance) { + if ((API.instance as any).server) await API.instance.teardown() - const knex = (Engine.instance.api as any).get?.('knexClient') + const knex = (API.instance as any).get?.('knexClient') if (knex) await knex.destroy() } diff --git a/packages/editor/src/components/EditorContainer.tsx b/packages/editor/src/components/EditorContainer.tsx index e62b06f908..d25487f4dd 100644 --- a/packages/editor/src/components/EditorContainer.tsx +++ b/packages/editor/src/components/EditorContainer.tsx @@ -51,8 +51,9 @@ import { DndWrapper } from './dnd/DndWrapper' import DragLayer from './dnd/DragLayer' import { useZendesk } from '@etherealengine/client-core/src/hooks/useZendesk' +import { API } from '@etherealengine/common' import { FeatureFlags } from '@etherealengine/common/src/constants/FeatureFlags' -import { Engine, EntityUUID } from '@etherealengine/ecs' +import { EntityUUID } from '@etherealengine/ecs' import useFeatureFlags from '@etherealengine/engine/src/useFeatureFlags' import { EngineState } from '@etherealengine/spatial/src/EngineState' import Button from '@etherealengine/ui/src/primitives/tailwind/Button' @@ -139,7 +140,7 @@ const EditorContainer = () => { if (!scenePath.value) return const abortController = new AbortController() - Engine.instance.api + API.instance .service(staticResourcePath) .find({ query: { key: scenePath.value, type: 'scene', $limit: 1 } diff --git a/packages/editor/src/components/assets/ModelCompressionPanel.tsx b/packages/editor/src/components/assets/ModelCompressionPanel.tsx index a41ea7364d..cc5863d116 100644 --- a/packages/editor/src/components/assets/ModelCompressionPanel.tsx +++ b/packages/editor/src/components/assets/ModelCompressionPanel.tsx @@ -27,10 +27,10 @@ import React, { useEffect } from 'react' import { twMerge } from 'tailwind-merge' import { Group, LoaderUtils } from 'three' +import { API } from '@etherealengine/common' import { modelTransformPath } from '@etherealengine/common/src/schema.type.module' import { createEntity, Entity, generateEntityUUID, UndefinedEntity, UUIDComponent } from '@etherealengine/ecs' import { getComponent, hasComponent, setComponent } from '@etherealengine/ecs/src/ComponentFunctions' -import { Engine } from '@etherealengine/ecs/src/Engine' import { DefaultModelTransformParameters as defaultParams, ModelTransformParameters @@ -111,7 +111,7 @@ export const createLODVariants = async ( transformMetadata[i][key] = data }) } else { - await Engine.instance.api.service(modelTransformPath).create(variant) + await API.instance.service(modelTransformPath).create(variant) } } diff --git a/packages/editor/src/components/dialogs/CreatePrefabPanelDialog.tsx b/packages/editor/src/components/dialogs/CreatePrefabPanelDialog.tsx index 94a889a7b0..f8a71bda01 100644 --- a/packages/editor/src/components/dialogs/CreatePrefabPanelDialog.tsx +++ b/packages/editor/src/components/dialogs/CreatePrefabPanelDialog.tsx @@ -24,18 +24,11 @@ Ethereal Engine. All Rights Reserved. */ import { PopoverState } from '@etherealengine/client-core/src/common/services/PopoverState' +import { API } from '@etherealengine/common' import config from '@etherealengine/common/src/config' import { staticResourcePath } from '@etherealengine/common/src/schema.type.module' import { pathJoin } from '@etherealengine/common/src/utils/miscUtils' -import { - Engine, - Entity, - createEntity, - entityExists, - getComponent, - removeEntity, - setComponent -} from '@etherealengine/ecs' +import { Entity, createEntity, entityExists, getComponent, removeEntity, setComponent } from '@etherealengine/ecs' import { GLTFDocumentState } from '@etherealengine/engine/src/gltf/GLTFDocumentState' import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent' import { SourceComponent } from '@etherealengine/engine/src/scene/components/SourceComponent' @@ -92,7 +85,7 @@ export default function CreatePrefabPanel({ entity }: { entity: Entity }) { getMutableState(SelectionState).selectedEntities.set([]) await exportRelativeGLTF(prefabEntity, srcProject, fileName) - const resources = await Engine.instance.api.service(staticResourcePath).find({ + const resources = await API.instance.service(staticResourcePath).find({ query: { key: 'projects/' + srcProject + '/' + fileName } }) if (resources.data.length === 0) { @@ -100,7 +93,7 @@ export default function CreatePrefabPanel({ entity }: { entity: Entity }) { } const resource = resources.data[0] const tags = [...prefabTag.value] - await Engine.instance.api.service(staticResourcePath).patch(resource.id, { tags: tags, project: srcProject }) + await API.instance.service(staticResourcePath).patch(resource.id, { tags: tags, project: srcProject }) removeEntity(prefabEntity) EditorControlFunctions.removeObject([entity]) diff --git a/packages/editor/src/components/realtime/EditorActiveInstanceService.ts b/packages/editor/src/components/realtime/EditorActiveInstanceService.ts index f27efa966c..cc966a2633 100644 --- a/packages/editor/src/components/realtime/EditorActiveInstanceService.ts +++ b/packages/editor/src/components/realtime/EditorActiveInstanceService.ts @@ -28,6 +28,7 @@ import { LocationInstanceState } from '@etherealengine/client-core/src/common/services/LocationInstanceConnectionService' import { AuthState } from '@etherealengine/client-core/src/user/services/AuthService' +import { API } from '@etherealengine/common' import logger from '@etherealengine/common/src/logger' import { InstanceActiveType, @@ -36,7 +37,6 @@ import { instanceActivePath, instanceProvisionPath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getMutableState, getState } from '@etherealengine/hyperflux' export const EditorActiveInstanceState = defineState({ @@ -49,7 +49,7 @@ export const EditorActiveInstanceState = defineState({ provisionServer: async (locationId: LocationID, instanceId: InstanceID, sceneId: string) => { logger.info({ locationId, instanceId, sceneId }, 'Provision World Server Editor') const token = getState(AuthState).authUser.accessToken - const provisionResult = await Engine.instance.api.service(instanceProvisionPath).find({ + const provisionResult = await API.instance.service(instanceProvisionPath).find({ query: { locationId: locationId, instanceId: instanceId, @@ -72,7 +72,7 @@ export const EditorActiveInstanceState = defineState({ getActiveInstances: async (sceneId: string) => { getMutableState(EditorActiveInstanceState).merge({ fetching: true }) - const activeInstances = await Engine.instance.api.service(instanceActivePath).find({ + const activeInstances = await API.instance.service(instanceActivePath).find({ query: { sceneId } }) getMutableState(EditorActiveInstanceState).merge({ activeInstances, fetching: false }) diff --git a/packages/editor/src/functions/EditorControlFunctions.test.tsx b/packages/editor/src/functions/EditorControlFunctions.test.tsx index 7542118123..f416e22779 100644 --- a/packages/editor/src/functions/EditorControlFunctions.test.tsx +++ b/packages/editor/src/functions/EditorControlFunctions.test.tsx @@ -52,7 +52,7 @@ describe('EditorControlFunctions', () => { createEngine() getMutableState(EngineState).isEditing.set(true) getMutableState(EngineState).isEditor.set(true) - Engine.instance.userID = 'user' as UserID + Engine.instance.store.userID = 'user' as UserID await Physics.load() physicsWorldEntity = createEntity() diff --git a/packages/editor/src/functions/assetFunctions.ts b/packages/editor/src/functions/assetFunctions.ts index 4f979bbe9f..5f2b1f57c3 100644 --- a/packages/editor/src/functions/assetFunctions.ts +++ b/packages/editor/src/functions/assetFunctions.ts @@ -28,9 +28,9 @@ import { CancelableUploadPromiseReturnType, uploadToFeathersService } from '@etherealengine/client-core/src/util/upload' +import { API } from '@etherealengine/common' import { assetLibraryPath, fileBrowserPath, fileBrowserUploadPath } from '@etherealengine/common/src/schema.type.module' import { processFileName } from '@etherealengine/common/src/utils/processFileName' -import { Engine } from '@etherealengine/ecs' import { modelResourcesPath } from '@etherealengine/engine/src/assets/functions/pathResolver' import { pathJoin } from '@etherealengine/common/src/utils/miscUtils' @@ -113,9 +113,9 @@ export const uploadProjectFiles = (projectName: string, files: File[], paths: st export async function clearModelResources(projectName: string, modelName: string) { const resourcePath = `projects/${projectName}/assets/${modelResourcesPath(modelName)}` - const exists = await Engine.instance.api.service(fileBrowserPath).get(resourcePath) + const exists = await API.instance.service(fileBrowserPath).get(resourcePath) if (exists) { - await Engine.instance.api.service(fileBrowserPath).remove(resourcePath) + await API.instance.service(fileBrowserPath).remove(resourcePath) } } @@ -188,7 +188,7 @@ export const getEntries = async (directoryReader: FileSystemDirectoryReader): Pr export const extractZip = async (path: string): Promise => { try { const params = { path: path } - await Engine.instance.api.service(assetLibraryPath).create(params) + await API.instance.service(assetLibraryPath).create(params) } catch (err) { console.error('error extracting zip: ', err) } diff --git a/packages/editor/src/functions/sceneFunctions.tsx b/packages/editor/src/functions/sceneFunctions.tsx index 6ee490ff1c..84d2732f42 100644 --- a/packages/editor/src/functions/sceneFunctions.tsx +++ b/packages/editor/src/functions/sceneFunctions.tsx @@ -25,13 +25,13 @@ Ethereal Engine. All Rights Reserved. import i18n from 'i18next' +import { API } from '@etherealengine/common' import config from '@etherealengine/common/src/config' import multiLogger from '@etherealengine/common/src/logger' import { StaticResourceType, fileBrowserPath, staticResourcePath } from '@etherealengine/common/src/schema.type.module' import { cleanString } from '@etherealengine/common/src/utils/cleanString' import { EntityUUID, UUIDComponent, UndefinedEntity } from '@etherealengine/ecs' import { getComponent, setComponent } from '@etherealengine/ecs/src/ComponentFunctions' -import { Engine } from '@etherealengine/ecs/src/Engine' import { GLTFComponent } from '@etherealengine/engine/src/gltf/GLTFComponent' import { GLTFDocumentState } from '@etherealengine/engine/src/gltf/GLTFDocumentState' import { GLTFSourceState } from '@etherealengine/engine/src/gltf/GLTFState' @@ -53,7 +53,7 @@ const logger = multiLogger.child({ component: 'editor:sceneFunctions' }) */ export const deleteScene = async (sceneKey: string): Promise => { try { - await Engine.instance.api.service(fileBrowserPath).remove(sceneKey) + await API.instance.service(fileBrowserPath).remove(sceneKey) } catch (error) { logger.error(error, 'Error in deleting project') throw error @@ -72,7 +72,7 @@ export const renameScene = async ( const oldName = resource.key.split('/').pop()! const newName = newKey.split('/').pop()! try { - return await Engine.instance.api + return await API.instance .service(fileBrowserPath) .update(null, { oldProject: projectName, newProject: projectName, oldPath, newPath, oldName, newName }, params) } catch (error) { @@ -99,7 +99,7 @@ export const saveSceneGLTF = async ( const currentSceneDirectory = getState(EditorState).scenePath!.split('/').slice(0, -1).join('/') if (saveAs) { - const existingScene = await Engine.instance.api.service(staticResourcePath).find({ + const existingScene = await API.instance.service(staticResourcePath).find({ query: { key: `${currentSceneDirectory}/${sceneName}.gltf`, $limit: 1 } }) @@ -114,7 +114,7 @@ export const saveSceneGLTF = async ( const blob = [JSON.stringify(encodedGLTF, null, 2)] const file = new File(blob, `${sceneName}.gltf`) - const currentScene = await Engine.instance.api.service(staticResourcePath).get(sceneAssetID) + const currentScene = await API.instance.service(staticResourcePath).get(sceneAssetID) const [[newPath]] = await Promise.all( uploadProjectFiles( @@ -136,7 +136,7 @@ export const saveSceneGLTF = async ( newURL.search = '' const assetURL = newURL.href.replace(fileServer, '').slice(1) // remove leading slash - const result = await Engine.instance.api.service(staticResourcePath).find({ + const result = await API.instance.service(staticResourcePath).find({ query: { key: assetURL, $limit: 1 } }) @@ -156,7 +156,7 @@ export const createScene = async ( projectName: string, templateURL = config.client.fileServer + '/projects/default-project/public/scenes/default.gltf' ) => { - const sceneData = await Engine.instance.api.service(fileBrowserPath).patch(null, { + const sceneData = await API.instance.service(fileBrowserPath).patch(null, { project: projectName, type: 'scene', body: templateURL, diff --git a/packages/engine/src/assets/compression/ModelTransformFunctions.ts b/packages/engine/src/assets/compression/ModelTransformFunctions.ts index 4cf1859fe5..22fd07d9ae 100644 --- a/packages/engine/src/assets/compression/ModelTransformFunctions.ts +++ b/packages/engine/src/assets/compression/ModelTransformFunctions.ts @@ -56,10 +56,10 @@ import { getPixels } from 'ndarray-pixels' import { LoaderUtils } from 'three' import { v4 as uuidv4 } from 'uuid' +import { API } from '@etherealengine/common' import config from '@etherealengine/common/src/config' import { fileBrowserPath } from '@etherealengine/common/src/schema.type.module' import { baseName, pathJoin } from '@etherealengine/common/src/utils/miscUtils' -import { Engine } from '@etherealengine/ecs/src/Engine' import { ExtractedImageTransformParameters, extractParameters, @@ -748,7 +748,7 @@ export async function transformModel( body: data, contentType: (await getContentType(args.dst)) || '' } - result = await Engine.instance.api.service('file-browser').patch(null, uploadArgs) + result = await API.instance.service('file-browser').patch(null, uploadArgs) */ /*dispatchAction( BufferHandlerExtension.saveBuffer({ @@ -794,8 +794,8 @@ export async function transformModel( ) const { json, resources } = await io.writeJSON(document, { format: Format.GLTF, basename: resourceName }) const folderURL = resourcePath.replace(config.client.fileServer, '') - //await Engine.instance.api.service(fileBrowserPath).remove(folderURL) - await Engine.instance.api.service(fileBrowserPath).create(folderURL) + //await API.instance.service(fileBrowserPath).remove(folderURL) + await API.instance.service(fileBrowserPath).create(folderURL) json.images?.map((image) => { const nuURI = pathJoin( @@ -827,7 +827,7 @@ export async function transformModel( body: data, contentType: (await getContentType(uri)) || '' } - return Engine.instance.api.service(fileBrowserPath).patch(null, args) + return API.instance.service(fileBrowserPath).patch(null, args) } await Promise.all(Object.entries(resources).map(([uri, data]) => doUpload(uri, data))) result = await doUpload(args.dst.replace(/\.glb$/, '.gltf'), Buffer.from(JSON.stringify(json))) diff --git a/packages/engine/src/avatar/functions/moveAvatar.test.tsx b/packages/engine/src/avatar/functions/moveAvatar.test.tsx index 4617fab756..612a061748 100644 --- a/packages/engine/src/avatar/functions/moveAvatar.test.tsx +++ b/packages/engine/src/avatar/functions/moveAvatar.test.tsx @@ -28,6 +28,7 @@ import { strictEqual } from 'assert' import React from 'react' import { Quaternion, Vector3 } from 'three' +import { API } from '@etherealengine/common' import { AvatarID, UserID } from '@etherealengine/common/src/schema.type.module' import { Entity, EntityUUID, SystemDefinitions, UUIDComponent } from '@etherealengine/ecs' import { getComponent, setComponent } from '@etherealengine/ecs/src/ComponentFunctions' @@ -56,7 +57,7 @@ describe('moveAvatar function tests', () => { createEngine() initializeSpatialEngine() await Physics.load() - Engine.instance.userID = 'userId' as UserID + Engine.instance.store.userID = 'userId' as UserID sceneEntity = loadEmptyScene() setComponent(sceneEntity, SceneComponent) physicsWorld = Physics.createWorld(getComponent(sceneEntity, UUIDComponent)) @@ -65,7 +66,7 @@ describe('moveAvatar function tests', () => { createMockNetwork() const eventDispatcher = new EventDispatcher() - ;(Engine.instance.api as any) = { + ;(API.instance as any) = { service: () => { return { on: (serviceName, cb) => { @@ -166,7 +167,7 @@ describe('moveAvatar function tests', () => { }) it('should take world.physics.timeScale into account when moving avatars, consistent with physics simulation', async () => { - Engine.instance.userID = 'user' as UserID + Engine.instance.store.userID = 'user' as UserID const ecsState = getMutableState(ECSState) ecsState.simulationTimestep.set(1000 / 60) @@ -209,7 +210,7 @@ describe('moveAvatar function tests', () => { }) it('should not allow velocity to breach a full unit through multiple frames', async () => { - Engine.instance.userID = 'user' as UserID + Engine.instance.store.userID = 'user' as UserID const ecsState = getMutableState(ECSState) ecsState.simulationTimestep.set(1000 / 60) diff --git a/packages/engine/src/avatar/functions/spawnAvatarReceptor.test.tsx b/packages/engine/src/avatar/functions/spawnAvatarReceptor.test.tsx index 1610740687..04e9d8bd81 100644 --- a/packages/engine/src/avatar/functions/spawnAvatarReceptor.test.tsx +++ b/packages/engine/src/avatar/functions/spawnAvatarReceptor.test.tsx @@ -28,6 +28,7 @@ import assert from 'assert' import React from 'react' import { Quaternion, Vector3 } from 'three' +import { API } from '@etherealengine/common' import { AvatarID, UserID } from '@etherealengine/common/src/schema.type.module' import { Entity, EntityUUID, SystemDefinitions, UUIDComponent } from '@etherealengine/ecs' import { getComponent, hasComponent, setComponent } from '@etherealengine/ecs/src/ComponentFunctions' @@ -59,7 +60,7 @@ describe('spawnAvatarReceptor', () => { initializeSpatialEngine() Engine.instance.store.defaultDispatchDelay = () => 0 await Physics.load() - Engine.instance.userID = 'user' as UserID + Engine.instance.store.userID = 'user' as UserID sceneEntity = loadEmptyScene() setComponent(sceneEntity, SceneComponent) @@ -69,7 +70,7 @@ describe('spawnAvatarReceptor', () => { createMockNetwork() const eventDispatcher = new EventDispatcher() - ;(Engine.instance.api as any) = { + ;(API.instance as any) = { service: () => { return { on: (serviceName, cb) => { diff --git a/packages/engine/src/avatar/state/AvatarNetworkState.tsx b/packages/engine/src/avatar/state/AvatarNetworkState.tsx index a02a8be9b5..5e99f63d6a 100644 --- a/packages/engine/src/avatar/state/AvatarNetworkState.tsx +++ b/packages/engine/src/avatar/state/AvatarNetworkState.tsx @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import { Paginated } from '@feathersjs/feathers' import React, { useEffect, useLayoutEffect } from 'react' +import { API } from '@etherealengine/common' import { AvatarID, avatarPath, AvatarType, userAvatarPath } from '@etherealengine/common/src/schema.type.module' import { isClient } from '@etherealengine/common/src/utils/getEnvironment' import { EntityUUID, getOptionalComponent, setComponent, UUIDComponent } from '@etherealengine/ecs' @@ -74,7 +75,7 @@ export const AvatarState = defineState({ }, selectRandomAvatar() { - Engine.instance.api + API.instance .service(avatarPath) .find({}) .then((avatars: Paginated) => { @@ -84,7 +85,7 @@ export const AvatarState = defineState({ }, updateUserAvatarId(avatarId: AvatarID) { - Engine.instance.api + API.instance .service(userAvatarPath) .patch(null, { avatarId: avatarId }, { query: { userId: Engine.instance.userID } }) .then(() => { @@ -122,7 +123,7 @@ const AvatarReactor = ({ entityUUID }: { entityUUID: EntityUUID }) => { useEffect(() => { let aborted = false - Engine.instance.api + API.instance .service(avatarPath) .get(avatarID.value!) .then((avatarDetails) => { diff --git a/packages/engine/src/interaction/systems/GrabbableSystem.test.ts b/packages/engine/src/interaction/systems/GrabbableSystem.test.ts index c1c38c1cec..da3b9f6255 100644 --- a/packages/engine/src/interaction/systems/GrabbableSystem.test.ts +++ b/packages/engine/src/interaction/systems/GrabbableSystem.test.ts @@ -131,7 +131,7 @@ describe.skip('EquippableSystem Integration Tests', () => { NetworkPeerFunctions.createPeer(NetworkState.worldNetwork, hostUserId, hostIndex, hostUserId, hostIndex) const userId = 'user id' as UserID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const grabbableEntity = createEntity() diff --git a/packages/engine/src/recording/ECSRecordingSystem.ts b/packages/engine/src/recording/ECSRecordingSystem.ts index 6bb82d9992..2955b3dcde 100644 --- a/packages/engine/src/recording/ECSRecordingSystem.ts +++ b/packages/engine/src/recording/ECSRecordingSystem.ts @@ -27,6 +27,7 @@ import { decode, encode } from 'msgpackr' import { PassThrough } from 'stream' import matches, { Validator } from 'ts-matches' +import { API } from '@etherealengine/common' import multiLogger from '@etherealengine/common/src/logger' import { RecordingID, @@ -189,7 +190,7 @@ export const RecordingState = defineState({ if (peerSchema.length) schema.peers[peerID] = peerSchema }) - const recording = await Engine.instance.api.service(recordingPath).create({ schema: schema }) + const recording = await API.instance.service(recordingPath).create({ schema: schema }) if (recording.id) RecordingState.startRecording({ recordingID: recording.id }) } catch (err) { @@ -363,7 +364,7 @@ export const dispatchError = (error: string, targetPeer: PeerID, topic: Topic) = } export const onStartRecording = async (action: ReturnType) => { - const api = Engine.instance.api + const api = API.instance const recording = await api.service(recordingPath).get(action.recordingID) if (!recording) return dispatchError('Recording not found', action.$peer, action.$topic) @@ -488,7 +489,7 @@ export const onStartRecording = async (action: ReturnType) => { - const api = Engine.instance.api + const api = API.instance const activeRecording = activeRecordings.get(action.recordingID) if (!activeRecording) return dispatchError('Recording not found', action.$peer, action.$topic) @@ -534,7 +535,7 @@ export const onStopRecording = async (action: ReturnType) => { - const api = Engine.instance.api + const api = API.instance const recording = await api.service(recordingPath).get(action.recordingID, { isInternal: true }) @@ -685,7 +686,7 @@ export const onStartPlayback = async (action: ReturnType) => { - const api = Engine.instance.api + const api = API.instance const recording = await api.service(recordingPath).get(action.recordingID) diff --git a/packages/hyperflux/functions/StoreFunctions.ts b/packages/hyperflux/functions/StoreFunctions.ts index 7d20f5010f..a4defa06ef 100644 --- a/packages/hyperflux/functions/StoreFunctions.ts +++ b/packages/hyperflux/functions/StoreFunctions.ts @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import { State } from '@hookstate/core' import { v4 as uuidv4 } from 'uuid' +import { UserID } from '@etherealengine/common/src/schema.type.module' import { PeerID } from '@etherealengine/hyperflux' import { ActionQueueHandle, ActionQueueInstance, ResolvedActionType, Topic } from './ActionFunctions' @@ -33,6 +34,11 @@ import { ReactorReconciler, ReactorRoot } from './ReactorFunctions' export type StringLiteral = T extends string ? (string extends T ? never : T) : never export interface HyperStore { + /** + * @todo temporarily moved public path from EngineState to here to treeshake properly. Will be moved in a further restructuring. + * An empty share link will default to the current URL, plus any modifiers (such as spectate mode) + */ + publicPath: string /** * The topic to dispatch to when none are supplied */ @@ -45,6 +51,10 @@ export interface HyperStore { * The agent id */ peerID: PeerID + /** + * The uuid of the logged-in user + */ + userID: UserID /** * A function which returns the current dispatch time (units are arbitrary) */ @@ -100,16 +110,19 @@ export class HyperFlux { } export function createHyperStore(options: { - getDispatchTime: () => number + publicPath: string + getDispatchTime?: () => number defaultDispatchDelay?: () => number getCurrentReactorRoot?: () => ReactorRoot | undefined }) { const store: HyperStore = { + publicPath: options.publicPath, defaultTopic: 'default' as Topic, forwardingTopics: new Set(), - getDispatchTime: options.getDispatchTime, + getDispatchTime: options.getDispatchTime ?? (() => 0), defaultDispatchDelay: options.defaultDispatchDelay ?? (() => 0), getCurrentReactorRoot: options.getCurrentReactorRoot ?? (() => undefined), + userID: '' as UserID, peerID: uuidv4() as PeerID, stateMap: {}, stateReactors: {}, diff --git a/packages/instanceserver/src/MediasoupRecordingSystem.ts b/packages/instanceserver/src/MediasoupRecordingSystem.ts index c546fec45d..5e2d54e20c 100644 --- a/packages/instanceserver/src/MediasoupRecordingSystem.ts +++ b/packages/instanceserver/src/MediasoupRecordingSystem.ts @@ -28,12 +28,12 @@ import { Consumer, PlainTransport, Router } from 'mediasoup/node/lib/types' import { useEffect } from 'react' import { PassThrough } from 'stream' +import { API } from '@etherealengine/common' import { RecordingID, recordingResourceUploadPath, RecordingSchemaType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineSystem } from '@etherealengine/ecs/src/SystemFunctions' import { PresentationSystemGroup } from '@etherealengine/ecs/src/SystemGroups' import { RecordingAPIState } from '@etherealengine/engine/src/recording/ECSRecordingSystem' @@ -203,7 +203,7 @@ type onUploadPartArgs = { // todo - refactor to be in a reactor such that we can record media tracks that are started after the recording is export const startMediaRecording = async (recordingID: RecordingID, schema: RecordingSchemaType['peers']) => { - const api = Engine.instance.api + const api = API.instance const network = NetworkState.mediaNetwork as SocketWebRTCServerNetwork const mediaStreams = {} as Record diff --git a/packages/instanceserver/src/NetworkFunctions.ts b/packages/instanceserver/src/NetworkFunctions.ts index add297ed15..cba2d48cb3 100755 --- a/packages/instanceserver/src/NetworkFunctions.ts +++ b/packages/instanceserver/src/NetworkFunctions.ts @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import _ from 'lodash' import { Spark } from 'primus' +import { API } from '@etherealengine/common' import { identityProviderPath, instanceAuthorizedUserPath, @@ -42,7 +43,6 @@ import { import { toDateTimeSql } from '@etherealengine/common/src/utils/datetime-sql' import { EntityUUID } from '@etherealengine/ecs' import { getComponent } from '@etherealengine/ecs/src/ComponentFunctions' -import { Engine } from '@etherealengine/ecs/src/Engine' import { AvatarComponent } from '@etherealengine/engine/src/avatar/components/AvatarComponent' import { AuthTask } from '@etherealengine/engine/src/avatar/functions/receiveJoinWorld' import { respawnAvatar } from '@etherealengine/engine/src/avatar/functions/respawnAvatar' @@ -67,7 +67,7 @@ const logger = multiLogger.child({ component: 'instanceserver:network' }) const isNameRegex = /instanceserver-([a-zA-Z0-9]{5}-[a-zA-Z0-9]{5})/ export const setupIPs = async () => { - const app = Engine.instance.api as Application + const app = API.instance as Application const serverState = getState(ServerState) const instanceServerState = getMutableState(InstanceServerState) @@ -269,7 +269,7 @@ const getUserSpawnFromInvite = async ( iteration = 0 ) => { if (inviteCode) { - const inviteCodeLookups = await Engine.instance.api.service(inviteCodeLookupPath).find({ + const inviteCodeLookups = await API.instance.service(inviteCodeLookupPath).find({ query: { inviteCode } @@ -343,7 +343,7 @@ export async function handleDisconnect(network: SocketWebRTCServerNetwork, peerI // This will only clear transports if the client's socketId matches the socket that's disconnecting. if (peerID === disconnectedClient?.peerID) { const instanceServerState = getState(InstanceServerState) - const app = Engine.instance.api as Application + const app = API.instance as Application if (!instanceServerState.isMediaInstance) { app diff --git a/packages/instanceserver/src/ServerHostNetworkSystem.tsx b/packages/instanceserver/src/ServerHostNetworkSystem.tsx index 4d6c8f7212..e17b115f81 100644 --- a/packages/instanceserver/src/ServerHostNetworkSystem.tsx +++ b/packages/instanceserver/src/ServerHostNetworkSystem.tsx @@ -24,6 +24,7 @@ Ethereal Engine. All Rights Reserved. */ import { useEffect } from 'react' +import { API } from '@etherealengine/common' import { RecordingID, recordingResourceUploadPath } from '@etherealengine/common/src/schema.type.module' import { Engine } from '@etherealengine/ecs/src/Engine' import { defineSystem } from '@etherealengine/ecs/src/SystemFunctions' @@ -58,7 +59,7 @@ export const uploadRecordingStaticResource = async (props: { body: Buffer mimeType: string }) => { - const api = Engine.instance.api + const api = API.instance await api.service(recordingResourceUploadPath).create({ recordingID: props.recordingID, diff --git a/packages/instanceserver/src/WebRTCFunctions.ts b/packages/instanceserver/src/WebRTCFunctions.ts index f55379b6ca..e4b6bbf690 100755 --- a/packages/instanceserver/src/WebRTCFunctions.ts +++ b/packages/instanceserver/src/WebRTCFunctions.ts @@ -38,7 +38,7 @@ import { import { decode } from 'msgpackr' import os from 'os' -import { Engine } from '@etherealengine/ecs/src/Engine' +import { API } from '@etherealengine/common' import { dispatchAction, getMutableState, getState, Identifiable, none, PeerID, State } from '@etherealengine/hyperflux' import { DataChannelRegistryState, @@ -399,7 +399,7 @@ export async function handleWebRtcTransportCreate( let { id, iceParameters, iceCandidates, dtlsParameters } = newTransport - const instanceServerSettingsResponse = await Engine.instance.api.service(instanceServerSettingPath).find() + const instanceServerSettingsResponse = await API.instance.service(instanceServerSettingPath).find() const webRTCSettings = instanceServerSettingsResponse.data[0].webRTCSettings const iceServers: { urls: string | string[] diff --git a/packages/instanceserver/src/channels.ts b/packages/instanceserver/src/channels.ts index ec99989535..daa5f0771f 100755 --- a/packages/instanceserver/src/channels.ts +++ b/packages/instanceserver/src/channels.ts @@ -249,7 +249,7 @@ const loadEngine = async ({ app, sceneId, headers }: { app: Application; sceneId const instanceServerState = getState(InstanceServerState) const hostId = instanceServerState.instance.id as UserID & InstanceID - Engine.instance.userID = hostId + Engine.instance.store.userID = hostId const topic = instanceServerState.isMediaInstance ? NetworkTopics.media : NetworkTopics.world HyperFlux.store.forwardingTopics.add(topic) diff --git a/packages/instanceserver/tests/InstanceLoad.test.ts b/packages/instanceserver/tests/InstanceLoad.test.ts index 2870356a4f..7dd7907e75 100644 --- a/packages/instanceserver/tests/InstanceLoad.test.ts +++ b/packages/instanceserver/tests/InstanceLoad.test.ts @@ -29,6 +29,7 @@ import assert from 'assert' import { ChildProcess } from 'child_process' import { v4 as uuidv4 } from 'uuid' +import { API } from '@etherealengine/common' import { identityProviderPath, InstanceData, @@ -37,7 +38,7 @@ import { RoomCode, UserID } from '@etherealengine/common/src/schema.type.module' -import { destroyEngine, Engine } from '@etherealengine/ecs/src/Engine' +import { destroyEngine } from '@etherealengine/ecs/src/Engine' import { getState } from '@etherealengine/hyperflux' import { NetworkState } from '@etherealengine/network' import { Application } from '@etherealengine/server-core/declarations' @@ -66,7 +67,7 @@ describe('InstanceLoad', () => { }) it('should load location', async () => { - const app = Engine.instance.api as Application + const app = API.instance as Application const loadLocation = onConnection(app) const type = 'guest' diff --git a/packages/network/src/EntityNetworkState.test.tsx b/packages/network/src/EntityNetworkState.test.tsx index 34429a97f7..7a1c5c80c5 100644 --- a/packages/network/src/EntityNetworkState.test.tsx +++ b/packages/network/src/EntityNetworkState.test.tsx @@ -71,7 +71,7 @@ describe('EntityNetworkState', () => { const peerID = Engine.instance.store.peerID const peerID2 = 'peer id 2' as PeerID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network = NetworkState.worldNetwork as Network NetworkPeerFunctions.createPeer(network, peerID, 0, hostUserId, 0) @@ -117,7 +117,7 @@ describe('EntityNetworkState', () => { const peerID = 'peer id' as PeerID const peerID2 = Engine.instance.store.peerID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network = NetworkState.worldNetwork as Network @@ -165,7 +165,7 @@ describe('EntityNetworkState', () => { const peerID2 = 'peer id 2' as PeerID const peerID3 = 'peer id 3' as PeerID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network = NetworkState.worldNetwork as Network NetworkPeerFunctions.createPeer(network, peerID, 0, hostUserId, 0) @@ -210,7 +210,7 @@ describe('EntityNetworkState', () => { const userId = 'user id' as UserID const peerID = Engine.instance.store.peerID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network = NetworkState.worldNetwork as Network NetworkPeerFunctions.createPeer(network, peerID, 1, userId, 1) @@ -247,7 +247,7 @@ describe('EntityNetworkState', () => { const peerID = Engine.instance.store.peerID const peerID2 = 'peer id 2' as PeerID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network = NetworkState.worldNetwork as Network NetworkPeerFunctions.createPeer(network, hostPeerId, 0, hostUserId, 0) @@ -317,7 +317,7 @@ describe('EntityNetworkState', () => { const peerID = Engine.instance.store.peerID const peerID2 = 'peer id 2' as PeerID - Engine.instance.userID = userId // user being the action dispatcher + Engine.instance.store.userID = userId // user being the action dispatcher const network = NetworkState.worldNetwork as Network NetworkPeerFunctions.createPeer(network, hostPeerId, 0, hostUserId, 0) @@ -385,7 +385,7 @@ describe('EntityNetworkState', () => { const peerID = Engine.instance.store.peerID const peerID2 = 'peer id 2' as PeerID - Engine.instance.userID = userId // user being the action dispatcher + Engine.instance.store.userID = userId // user being the action dispatcher const network = NetworkState.worldNetwork as Network NetworkPeerFunctions.createPeer(network, hostPeerId, 0, hostUserId, 0) diff --git a/packages/network/src/EntityNetworkState.tsx b/packages/network/src/EntityNetworkState.tsx index 27b6afd3f2..c803f52ad4 100644 --- a/packages/network/src/EntityNetworkState.tsx +++ b/packages/network/src/EntityNetworkState.tsx @@ -181,7 +181,7 @@ const OwnerPeerReactor = (props: { uuid: EntityUUID }) => { return () => { // ensure reactor isn't completely unmounting if (!getState(EntityNetworkState)[props.uuid]) return - if (ownerPeer !== Engine.instance.store.peerID && Engine.instance.userID === state.ownerId.value) { + if (ownerPeer !== Engine.instance.store.peerID && Engine.instance.store.userID === state.ownerId.value) { const lowestPeer = [...networkState.users[Engine.instance.userID].value].sort((a, b) => (a > b ? 1 : -1))[0] if (lowestPeer !== Engine.instance.store.peerID) return dispatchAction( diff --git a/packages/network/src/functions/NetworkPeerFunctions.test.tsx b/packages/network/src/functions/NetworkPeerFunctions.test.tsx index 23797dc425..f1e4b57f4e 100644 --- a/packages/network/src/functions/NetworkPeerFunctions.test.tsx +++ b/packages/network/src/functions/NetworkPeerFunctions.test.tsx @@ -55,7 +55,7 @@ describe('NetworkPeerFunctions', () => { it('should add peer', () => { const userId = 'user id' as UserID const peerID = Engine.instance.store.peerID - Engine.instance.userID = 'another user id' as UserID + Engine.instance.store.userID = 'another user id' as UserID const userIndex = 1 const peerIndex = 2 @@ -77,7 +77,7 @@ describe('NetworkPeerFunctions', () => { it('should update peer if it already exists', () => { const userId = 'user id' as UserID const peerID = Engine.instance.store.peerID - Engine.instance.userID = 'another user id' as UserID + Engine.instance.store.userID = 'another user id' as UserID const userIndex = 1 const userIndex2 = 2 @@ -103,7 +103,7 @@ describe('NetworkPeerFunctions', () => { it('should remove peer', () => { const userId = 'user id' as UserID const peerID = 'peer id' as PeerID - Engine.instance.userID = 'another user id' as UserID + Engine.instance.store.userID = 'another user id' as UserID const userIndex = 1 const peerIndex = 2 const network = NetworkState.worldNetwork as Network @@ -122,7 +122,7 @@ describe('NetworkPeerFunctions', () => { it('should not remove self peer', () => { const userId = 'user id' as UserID const peerID = Engine.instance.store.peerID - Engine.instance.userID = 'another user id' as UserID + Engine.instance.store.userID = 'another user id' as UserID const userIndex = 1 const peerIndex = 2 @@ -142,7 +142,7 @@ describe('NetworkPeerFunctions', () => { it('should remove peer and owned network objects', async () => { const userId = 'world' as UserID & InstanceID const anotherPeerID = 'another peer id' as PeerID - Engine.instance.userID = 'another user id' as UserID + Engine.instance.store.userID = 'another user id' as UserID const userIndex = 1 const peerIndex = 5 const network = NetworkState.worldNetwork as Network diff --git a/packages/network/src/serialization/DataReader.test.ts b/packages/network/src/serialization/DataReader.test.ts index b1fda4239d..e3e5126c39 100644 --- a/packages/network/src/serialization/DataReader.test.ts +++ b/packages/network/src/serialization/DataReader.test.ts @@ -545,7 +545,7 @@ describe('DataReader', () => { const networkId = 5678 as NetworkId const userID = 'user id' as UserID const peerID = 'peer id' as PeerID - Engine.instance.userID = userID + Engine.instance.store.userID = userID const userIndex = 0 const peerIndex = 0 @@ -624,7 +624,7 @@ describe('DataReader', () => { const networkId = 5678 as NetworkId const userID = 'user Id' as UserID const peerID = 'peer ID' as PeerID - Engine.instance.userID = userID + Engine.instance.store.userID = userID const userIndex = 0 const peerIndex = 0 @@ -691,7 +691,7 @@ describe('DataReader', () => { const peerID = 'peer id' as PeerID const peerID2 = 'peer id 2' as PeerID - Engine.instance.userID = userID + Engine.instance.store.userID = userID const userIndex = 0 const peerIndex = 0 const peer2Index = 1 @@ -850,7 +850,7 @@ describe('DataReader', () => { const write = createDataWriter() const network = NetworkState.worldNetwork as Network - Engine.instance.userID = 'userId' as UserID + Engine.instance.store.userID = 'userId' as UserID const userId = Engine.instance.userID const peerID = Engine.instance.store.peerID const userIndex = 0 diff --git a/packages/projects/loadEngineInjection.ts b/packages/projects/loadEngineInjection.ts index 471185496e..cc9a17fd00 100644 --- a/packages/projects/loadEngineInjection.ts +++ b/packages/projects/loadEngineInjection.ts @@ -23,13 +23,13 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import { API } from '@etherealengine/common' import { projectsPath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { loadConfigForProject } from './loadConfigForProject' export const loadEngineInjection = async () => { - const projects = await Engine.instance.api.service(projectsPath).find() + const projects = await API.instance.service(projectsPath).find() return Promise.all( projects.map(async (project) => { try { diff --git a/packages/projects/loadWebappInjection.ts b/packages/projects/loadWebappInjection.ts index a8a05c30b6..d08e152b0f 100644 --- a/packages/projects/loadWebappInjection.ts +++ b/packages/projects/loadWebappInjection.ts @@ -23,14 +23,14 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import { API } from '@etherealengine/common' import { projectsPath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { loadConfigForProject } from './loadConfigForProject' export const loadWebappInjection = async () => { if (window.location.pathname.startsWith('/auth/oauth')) return [] - const projects = await Engine.instance.api.service(projectsPath).find() + const projects = await API.instance.service(projectsPath).find() return ( await Promise.all( projects.map(async (project) => { diff --git a/packages/server-core/src/createApp.ts b/packages/server-core/src/createApp.ts index 27da518a85..0919e68d61 100644 --- a/packages/server-core/src/createApp.ts +++ b/packages/server-core/src/createApp.ts @@ -38,11 +38,11 @@ import cors from 'koa-cors' import helmet from 'koa-helmet' import healthcheck from 'koa-simple-healthcheck' +import { API } from '@etherealengine/common' import { pipeLogs } from '@etherealengine/common/src/logger' import { pipe } from '@etherealengine/common/src/utils/pipe' -import { Engine, createEngine } from '@etherealengine/ecs/src/Engine' -import { getMutableState } from '@etherealengine/hyperflux' -import { EngineState } from '@etherealengine/spatial/src/EngineState' +import { createEngine } from '@etherealengine/ecs/src/Engine' +import { createHyperStore, getMutableState } from '@etherealengine/hyperflux' import { Application } from '../declarations' import { logger } from './ServerLogger' @@ -174,6 +174,7 @@ export const createFeathersKoaApp = ( serverMode: ServerTypeMode = ServerMode.API, configurationPipe = serverPipe ): Application => { + createHyperStore({ publicPath: config.client.dist }) createEngine() const serverState = getMutableState(ServerState) @@ -185,10 +186,8 @@ export const createFeathersKoaApp = ( createIPFSStorageProvider() } - getMutableState(EngineState).publicPath.set(config.client.dist) - const app = koa(feathers()) as Application - Engine.instance.api = app + API.instance = app app.set('nextReadyEmitter', new EventEmitter()) @@ -260,7 +259,7 @@ export const createFeathersKoaApp = ( } }) - pipeLogs(Engine.instance.api) + pipeLogs(API.instance) return app } diff --git a/packages/spatial/src/EngineState.ts b/packages/spatial/src/EngineState.ts index ec418dbc13..3d9de748f7 100644 --- a/packages/spatial/src/EngineState.ts +++ b/packages/spatial/src/EngineState.ts @@ -29,10 +29,6 @@ import { defineState } from '@etherealengine/hyperflux' export const EngineState = defineState({ name: 'EngineState', initial: { - /** - * An empty share link will default to the current URL, plus any modifiers (such as spectate mode) - */ - publicPath: '', /** @deprecated use isEditing instead */ isEditor: false, isEditing: false, diff --git a/packages/spatial/src/camera/systems/CameraSystem.test.tsx b/packages/spatial/src/camera/systems/CameraSystem.test.tsx index 259b8d4b1e..bb0004d38a 100755 --- a/packages/spatial/src/camera/systems/CameraSystem.test.tsx +++ b/packages/spatial/src/camera/systems/CameraSystem.test.tsx @@ -81,7 +81,7 @@ describe('CameraSystem', async () => { const peerID2 = 'peer id 2' as PeerID const CameraUUID = UUIDComponent.generateUUID() - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network: Network = NetworkState.worldNetwork NetworkPeerFunctions.createPeer(network, peerID, 0, hostUserId, 0) diff --git a/packages/spatial/src/camera/systems/SpectateSystem.test.tsx b/packages/spatial/src/camera/systems/SpectateSystem.test.tsx index 63486da2ea..d508fa0d45 100644 --- a/packages/spatial/src/camera/systems/SpectateSystem.test.tsx +++ b/packages/spatial/src/camera/systems/SpectateSystem.test.tsx @@ -80,7 +80,7 @@ describe('SpectateSystem', async () => { const peerID3 = 'peer id 3' as PeerID const spectatorID = 'spectator id' as UserID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network: Network = NetworkState.worldNetwork NetworkPeerFunctions.createPeer(network, peerID, 0, hostUserId, 0) @@ -115,7 +115,7 @@ describe('SpectateSystem', async () => { const peerID3 = 'peer id 3' as PeerID const spectatorID = 'spectator id' as UserID - Engine.instance.userID = userId + Engine.instance.store.userID = userId const network: Network = NetworkState.worldNetwork NetworkPeerFunctions.createPeer(network, peerID, 0, hostUserId, 0) diff --git a/packages/spatial/src/common/functions/FeathersHooks.test.ts b/packages/spatial/src/common/functions/FeathersHooks.test.ts index ce8a7d70b3..6e0af6bd4f 100644 --- a/packages/spatial/src/common/functions/FeathersHooks.test.ts +++ b/packages/spatial/src/common/functions/FeathersHooks.test.ts @@ -29,9 +29,10 @@ import { afterEach } from 'mocha' import { useEffect } from 'react' import { AvatarID, UserName, userPath } from '@etherealengine/common/src/schema.type.module' -import { Engine, destroyEngine } from '@etherealengine/ecs/src/Engine' +import { destroyEngine } from '@etherealengine/ecs/src/Engine' import { createState } from '@etherealengine/hyperflux' +import { API } from '@etherealengine/common' import { createEngine } from '@etherealengine/ecs/src/Engine' import { EventDispatcher } from '../classes/EventDispatcher' import { useFind, useGet, useMutation } from './FeathersHooks' @@ -46,7 +47,7 @@ describe('FeathersHooks', () => { { id: '2', name: 'Jane' as UserName } ] eventDispatcher = new EventDispatcher() - ;(Engine.instance.api as any) = { + ;(API.instance as any) = { service: () => { return { find: () => { @@ -287,7 +288,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api + API.instance .service(userPath) .create({ name: 'Jack' as UserName, avatarId: '' as AvatarID, isGuest: true, scopes: [] }) }) @@ -310,7 +311,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api + API.instance .service(userPath) .create({ name: 'Jack' as UserName, avatarId: '' as AvatarID, isGuest: true, scopes: [] }) }) @@ -330,7 +331,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api.service(userPath).update('1', { name: 'Jack' as UserName }) + API.instance.service(userPath).update('1', { name: 'Jack' as UserName }) }) await act(() => { rerender() @@ -350,7 +351,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api.service(userPath).update('1', { name: 'Jack' as UserName }) + API.instance.service(userPath).update('1', { name: 'Jack' as UserName }) }) await act(() => { rerender() @@ -368,7 +369,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api.service(userPath).patch('1', { name: 'Jack' as UserName }) + API.instance.service(userPath).patch('1', { name: 'Jack' as UserName }) }) await act(() => { rerender() @@ -388,7 +389,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api.service(userPath).patch('1', { name: 'Jack' as UserName }) + API.instance.service(userPath).patch('1', { name: 'Jack' as UserName }) }) await act(() => { rerender() @@ -406,7 +407,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api.service(userPath).remove('1') + API.instance.service(userPath).remove('1') }) await act(() => { rerender() @@ -426,7 +427,7 @@ describe('FeathersHooks', () => { rerender() }) await act(() => { - Engine.instance.api.service(userPath).remove('1') + API.instance.service(userPath).remove('1') }) await act(() => { rerender() diff --git a/packages/spatial/src/common/functions/FeathersHooks.tsx b/packages/spatial/src/common/functions/FeathersHooks.tsx index 4991678cd4..2cdb6ce498 100644 --- a/packages/spatial/src/common/functions/FeathersHooks.tsx +++ b/packages/spatial/src/common/functions/FeathersHooks.tsx @@ -38,9 +38,9 @@ Ethereal Engine. All Rights Reserved. import { Params, Query } from '@feathersjs/feathers' import React, { useCallback, useEffect, useLayoutEffect, useMemo } from 'react' +import { API } from '@etherealengine/common' import { ServiceTypes } from '@etherealengine/common/declarations' import { OpaqueType } from '@etherealengine/common/src/interfaces/OpaqueType' -import { Engine } from '@etherealengine/ecs/src/Engine' import { defineState, getState, NO_PROXY, State, useHookstate, useMutableState } from '@etherealengine/hyperflux' export type Methods = 'find' | 'get' | 'create' | 'update' | 'patch' | 'remove' @@ -116,7 +116,7 @@ export const useService = ( method: M, ...args: Args ) => { - const service = Engine.instance.api.service(serviceName) + const service = API.instance.service(serviceName) const state = useMutableState(FeathersState) const queryParams = { @@ -323,7 +323,7 @@ function useMethod( ) { return useCallback( (...args) => { - const service = Engine.instance.api.service(serviceName) + const service = API.instance.service(serviceName) state.merge({ status: 'loading', loading: true, data: null, error: null }) return service[method](...args) .then((item) => { @@ -362,7 +362,7 @@ export function useRealtime( refetch: (data: any, eventType: 'created' | 'updated' | 'patched' | 'removed') => void ) { useLayoutEffect(() => { - const service = Engine.instance.api.service(serviceName) + const service = API.instance.service(serviceName) const handleCreated = (data: any) => refetch(data, 'created') const handleUpdated = (data: any) => refetch(data, 'updated') diff --git a/packages/spatial/src/common/functions/checkScope.ts b/packages/spatial/src/common/functions/checkScope.ts index e95ed1cfac..0472f1db4a 100644 --- a/packages/spatial/src/common/functions/checkScope.ts +++ b/packages/spatial/src/common/functions/checkScope.ts @@ -23,11 +23,11 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20 Ethereal Engine. All Rights Reserved. */ +import { API } from '@etherealengine/common' import { scopePath, ScopeTypeInterface, UserType } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' export const checkScope = async (user: UserType, currentType: string, scopeToVerify: string) => { - const scopes = (await Engine.instance.api.service(scopePath).find({ + const scopes = (await API.instance.service(scopePath).find({ query: { userId: user.id, paginate: false diff --git a/packages/ui/src/components/editor/panels/Assets/container/index.tsx b/packages/ui/src/components/editor/panels/Assets/container/index.tsx index 62de188807..ce5b97f469 100644 --- a/packages/ui/src/components/editor/panels/Assets/container/index.tsx +++ b/packages/ui/src/components/editor/panels/Assets/container/index.tsx @@ -30,12 +30,12 @@ import { useTranslation } from 'react-i18next' import { NotificationService } from '@etherealengine/client-core/src/common/services/NotificationService' import { PopoverState } from '@etherealengine/client-core/src/common/services/PopoverState' import { AuthState } from '@etherealengine/client-core/src/user/services/AuthService' +import { API } from '@etherealengine/common' import { StaticResourceQuery, StaticResourceType, staticResourcePath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs/src/Engine' import { AssetsPanelCategories } from '@etherealengine/editor/src/components/assets/AssetsPanelCategories' import { AssetSelectionChangePropsType } from '@etherealengine/editor/src/components/assets/AssetsPreviewPanel' import { FilesViewModeSettings } from '@etherealengine/editor/src/components/assets/FileBrowser/FileBrowserState' @@ -531,7 +531,7 @@ const AssetPanel = () => { $skip: Math.min(staticResourcesPagination.skip.value, staticResourcesPagination.total.value) } as StaticResourceQuery - Engine.instance.api + API.instance .service(staticResourcePath) .find({ query }) .then((resources) => { diff --git a/packages/ui/src/components/editor/panels/Files/browserGrid/FilePropertiesModal.tsx b/packages/ui/src/components/editor/panels/Files/browserGrid/FilePropertiesModal.tsx index 0b3c01b890..6b7a638733 100644 --- a/packages/ui/src/components/editor/panels/Files/browserGrid/FilePropertiesModal.tsx +++ b/packages/ui/src/components/editor/panels/Files/browserGrid/FilePropertiesModal.tsx @@ -28,8 +28,8 @@ import { useTranslation } from 'react-i18next' import { FileThumbnailJobState } from '@etherealengine/client-core/src/common/services/FileThumbnailJobState' import { PopoverState } from '@etherealengine/client-core/src/common/services/PopoverState' +import { API } from '@etherealengine/common' import { StaticResourceType, UserType, staticResourcePath } from '@etherealengine/common/src/schema.type.module' -import { Engine } from '@etherealengine/ecs' import { ImmutableArray, NO_PROXY, State, getMutableState, useHookstate } from '@etherealengine/hyperflux' import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks' import { HiPencil, HiPlus, HiXMark } from 'react-icons/hi2' @@ -99,7 +99,7 @@ export default function FilePropertiesModal({ for (const resource of fileStaticResources.value) { const oldTags = resource.tags ?? [] const newTags = Array.from(new Set([...addedTags, ...oldTags.filter((tag) => !removedTags.includes(tag))])) - await Engine.instance.api.service(staticResourcePath).patch(resource.id, { + await API.instance.service(staticResourcePath).patch(resource.id, { key: resource.key, tags: newTags, licensing: resourceDigest.licensing.value, @@ -125,7 +125,7 @@ export default function FilePropertiesModal({ const resources = useFind(staticResourcePath, { query }) useEffect(() => { if (resources.data.length === 0) return - Engine.instance.api + API.instance .service('user') .get(resources.data[0].userId) .then((user) => author.set(user)) diff --git a/packages/ui/src/components/editor/panels/Files/download/projectDownload.tsx b/packages/ui/src/components/editor/panels/Files/download/projectDownload.tsx index bb6b4406dc..fc5a347096 100644 --- a/packages/ui/src/components/editor/panels/Files/download/projectDownload.tsx +++ b/packages/ui/src/components/editor/panels/Files/download/projectDownload.tsx @@ -24,10 +24,10 @@ Ethereal Engine. All Rights Reserved. */ import { NotificationService } from '@etherealengine/client-core/src/common/services/NotificationService' +import { API } from '@etherealengine/common' import config from '@etherealengine/common/src/config' import { archiverPath } from '@etherealengine/common/src/schema.type.module' import { bytesToSize } from '@etherealengine/common/src/utils/btyesToSize' -import { Engine } from '@etherealengine/ecs' import { downloadBlobAsZip } from '@etherealengine/editor/src/functions/assetFunctions' import { defineState, getMutableState, useMutableState } from '@etherealengine/hyperflux' import React from 'react' @@ -44,7 +44,7 @@ const DownloadProjectState = defineState({ }) export const handleDownloadProject = async (projectName: string, selectedDirectory: string) => { - const data = await Engine.instance.api + const data = await API.instance .service(archiverPath) .get(null, { query: { project: projectName } }) .catch((err: Error) => { diff --git a/packages/ui/src/components/editor/panels/Materials/container/index.tsx b/packages/ui/src/components/editor/panels/Materials/container/index.tsx index 38a32339b5..5a7eee216b 100644 --- a/packages/ui/src/components/editor/panels/Materials/container/index.tsx +++ b/packages/ui/src/components/editor/panels/Materials/container/index.tsx @@ -27,9 +27,10 @@ import React, { useEffect } from 'react' import AutoSizer from 'react-virtualized-auto-sizer' import { FixedSizeList } from 'react-window' +import { API } from '@etherealengine/common' import { staticResourcePath } from '@etherealengine/common/src/schema.type.module' import { pathJoin } from '@etherealengine/common/src/utils/miscUtils' -import { Engine, EntityUUID, getComponent, getOptionalComponent, useQuery, UUIDComponent } from '@etherealengine/ecs' +import { EntityUUID, getComponent, getOptionalComponent, useQuery, UUIDComponent } from '@etherealengine/ecs' import { uploadProjectFiles } from '@etherealengine/editor/src/functions/assetFunctions' import { EditorState } from '@etherealengine/editor/src/services/EditorServices' import { ImportSettingsState } from '@etherealengine/editor/src/services/ImportSettingsState' @@ -140,7 +141,7 @@ export default function MaterialLibraryPanel() { ) const adjustedLibraryName = libraryName.length > 0 ? libraryName.substring(1) : '' const key = `projects/${projectName}${importSettings.importFolder}${adjustedLibraryName}` - const resources = await Engine.instance.api.service(staticResourcePath).find({ + const resources = await API.instance.service(staticResourcePath).find({ query: { key: key } }) if (resources.data.length === 0) { @@ -148,9 +149,7 @@ export default function MaterialLibraryPanel() { } const resource = resources.data[0] const tags = ['Material'] - await Engine.instance.api - .service(staticResourcePath) - .patch(resource.id, { tags: tags, project: projectName }) + await API.instance.service(staticResourcePath).patch(resource.id, { tags: tags, project: projectName }) console.log('exported material data to ', ...urls) }} > diff --git a/packages/ui/src/components/editor/properties/model/transform/index.tsx b/packages/ui/src/components/editor/properties/model/transform/index.tsx index e8b707de32..f0f9ec12f3 100644 --- a/packages/ui/src/components/editor/properties/model/transform/index.tsx +++ b/packages/ui/src/components/editor/properties/model/transform/index.tsx @@ -26,6 +26,7 @@ Ethereal Engine. All Rights Reserved. import React, { useCallback, useEffect } from 'react' import { DoubleSide, Mesh } from 'three' +import { API } from '@etherealengine/common' import { modelTransformPath } from '@etherealengine/common/src/schema.type.module' import { ComponentType, @@ -33,7 +34,6 @@ import { hasComponent, useComponent } from '@etherealengine/ecs/src/ComponentFunctions' -import { Engine } from '@etherealengine/ecs/src/Engine' import { Entity } from '@etherealengine/ecs/src/Entity' import exportGLTF from '@etherealengine/editor/src/functions/exportGLTF' import { SelectionState } from '@etherealengine/editor/src/services/SelectionServices' @@ -141,7 +141,7 @@ export default function ModelTransformProperties({ entity, onChangeModel }: { en if (clientside) { nuPath = await clientSideTransformModel(variant as ModelTransformParameters) } else { - await Engine.instance.api.service(modelTransformPath).create(variant) + await API.instance.service(modelTransformPath).create(variant) } } @@ -189,7 +189,7 @@ export default function ModelTransformProperties({ entity, onChangeModel }: { en console.log('saved baked model') //perform gltf transform console.log('transforming model at ' + bakedPath + '...') - const transformedPath = await Engine.instance.api.service(modelTransformPath).create(transformParms.value) + const transformedPath = await API.instance.service(modelTransformPath).create(transformParms.value) console.log('transformed model into ' + transformedPath) onChangeModel(transformedPath) } diff --git a/packages/ui/src/pages/Capture/index.stories.tsx b/packages/ui/src/pages/Capture/index.stories.tsx index 0241775531..ad6ef3b80e 100644 --- a/packages/ui/src/pages/Capture/index.stories.tsx +++ b/packages/ui/src/pages/Capture/index.stories.tsx @@ -81,7 +81,7 @@ const decorators = [ }, [selfUser, projectState.updateNeeded.value]) useEffect(() => { - Engine.instance.userID = selfUser.id.value + Engine.instance.store.userID = selfUser.id.value }, [selfUser.id]) useEffect(() => { From 2660b7aa8e8d4b4bb5b24e89f7a508bc3d4d7065 Mon Sep 17 00:00:00 2001 From: HexaField Date: Sat, 17 Aug 2024 11:40:49 +1000 Subject: [PATCH 3/5] license --- packages/common/index.ts | 25 +++++++++++++++++++++++++ packages/common/src/API.ts | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/packages/common/index.ts b/packages/common/index.ts index 7038406043..1fdf103def 100644 --- a/packages/common/index.ts +++ b/packages/common/index.ts @@ -1 +1,26 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + export { API } from './src/API' diff --git a/packages/common/src/API.ts b/packages/common/src/API.ts index 75af45e43b..0858d52336 100644 --- a/packages/common/src/API.ts +++ b/packages/common/src/API.ts @@ -1,3 +1,28 @@ +/* +CPAL-1.0 License + +The contents of this file are subject to the Common Public Attribution License +Version 1.0. (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE. +The License is based on the Mozilla Public License Version 1.1, but Sections 14 +and 15 have been added to cover use of software over a computer network and +provide for limited attribution for the Original Developer. In addition, +Exhibit A has been modified to be consistent with Exhibit B. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the +specific language governing rights and limitations under the License. + +The Original Code is Ethereal Engine. + +The Original Developer is the Initial Developer. The Initial Developer of the +Original Code is the Ethereal Engine team. + +All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023 +Ethereal Engine. All Rights Reserved. +*/ + import { FeathersApplication } from '@feathersjs/feathers' import { ServiceTypes } from '../declarations' From 2449463d75e18dde4d592252b07e59ef8d3783b1 Mon Sep 17 00:00:00 2001 From: HexaField Date: Sat, 17 Aug 2024 11:45:49 +1000 Subject: [PATCH 4/5] offline page --- packages/client/src/pages/offline/offline.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/client/src/pages/offline/offline.tsx b/packages/client/src/pages/offline/offline.tsx index bd699872da..1252d32a59 100644 --- a/packages/client/src/pages/offline/offline.tsx +++ b/packages/client/src/pages/offline/offline.tsx @@ -27,6 +27,8 @@ import { t } from 'i18next' import React, { Suspense } from 'react' import { Route, Routes } from 'react-router-dom' +import '../../engine' + import { useEngineInjection } from '@etherealengine/client-core/src/components/World/EngineHooks' import LocationPage from '@etherealengine/client-core/src/world/Location' import LoadingView from '@etherealengine/ui/src/primitives/tailwind/LoadingView' From cfca06f84f18235a1ba2e79c939c05314e95dfe3 Mon Sep 17 00:00:00 2001 From: HexaField Date: Sat, 17 Aug 2024 11:54:51 +1000 Subject: [PATCH 5/5] fix public path --- packages/engine/src/assets/classes/AssetLoader.ts | 4 ++-- packages/engine/src/assets/functions/createGLTFLoader.ts | 7 +++---- .../engine/src/scene/components/NewVolumetricComponent.ts | 4 ++-- packages/engine/src/scene/components/UVOL1Component.ts | 3 +-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/engine/src/assets/classes/AssetLoader.ts b/packages/engine/src/assets/classes/AssetLoader.ts index 888b6d102f..7e2dbb9364 100644 --- a/packages/engine/src/assets/classes/AssetLoader.ts +++ b/packages/engine/src/assets/classes/AssetLoader.ts @@ -27,9 +27,9 @@ import { AudioLoader } from 'three' import { getState } from '@etherealengine/hyperflux' import { isAbsolutePath } from '@etherealengine/spatial/src/common/functions/isAbsolutePath' -import { EngineState } from '@etherealengine/spatial/src/EngineState' import { AssetExt, AssetType, FileToAssetExt, FileToAssetType } from '@etherealengine/common/src/constants/AssetType' +import { Engine } from '@etherealengine/ecs' import loadVideoTexture from '../../scene/materials/functions/LoadVideoTexture' import { FileLoader } from '../loaders/base/FileLoader' import { DDSLoader } from '../loaders/dds/DDSLoader' @@ -90,7 +90,7 @@ export const getLoader = (assetType: AssetExt) => { } } -const getAbsolutePath = (url) => (isAbsolutePath(url) ? url : getState(EngineState).publicPath + url) +const getAbsolutePath = (url) => (isAbsolutePath(url) ? url : Engine.instance.store.publicPath + url) const loadAsset = async ( url: string, diff --git a/packages/engine/src/assets/functions/createGLTFLoader.ts b/packages/engine/src/assets/functions/createGLTFLoader.ts index 2ba03fed14..a37c941f45 100644 --- a/packages/engine/src/assets/functions/createGLTFLoader.ts +++ b/packages/engine/src/assets/functions/createGLTFLoader.ts @@ -27,9 +27,8 @@ import { VRMLoaderPlugin } from '@pixiv/three-vrm' import { Group, WebGLRenderer } from 'three' import { isClient } from '@etherealengine/common/src/utils/getEnvironment' -import { getState } from '@etherealengine/hyperflux' -import { EngineState } from '@etherealengine/spatial/src/EngineState' +import { Engine } from '@etherealengine/ecs' import { DRACOLoader } from '../loaders/gltf/DRACOLoader' import { CachedImageLoadExtension } from '../loaders/gltf/extensions/CachedImageLoadExtension' import EEECSImporterExtension from '../loaders/gltf/extensions/EEECSImporterExtension' @@ -47,7 +46,7 @@ import { loadDRACODecoderNode, NodeDRACOLoader } from '../loaders/gltf/NodeDraco export const initializeKTX2Loader = (loader: GLTFLoader) => { const ktxLoader = new KTX2Loader() - ktxLoader.setTranscoderPath(getState(EngineState).publicPath + '/loader_decoders/basis/') + ktxLoader.setTranscoderPath(Engine.instance.store.publicPath + '/loader_decoders/basis/') const renderer = new WebGLRenderer() ktxLoader.detectSupport(renderer) renderer.dispose() @@ -80,7 +79,7 @@ export const createGLTFLoader = (keepMaterials = false) => { if (isClient) { initializeKTX2Loader(loader) const dracoLoader = new DRACOLoader() - dracoLoader.setDecoderPath(getState(EngineState).publicPath + '/loader_decoders/') + dracoLoader.setDecoderPath(Engine.instance.store.publicPath + '/loader_decoders/') dracoLoader.setWorkerLimit(1) loader.setDRACOLoader(dracoLoader) } else { diff --git a/packages/engine/src/scene/components/NewVolumetricComponent.ts b/packages/engine/src/scene/components/NewVolumetricComponent.ts index 1be09f6f1e..74c64c3700 100644 --- a/packages/engine/src/scene/components/NewVolumetricComponent.ts +++ b/packages/engine/src/scene/components/NewVolumetricComponent.ts @@ -25,6 +25,7 @@ Ethereal Engine. All Rights Reserved. import { AnimationSystemGroup, + Engine, Entity, defineComponent, getComponent, @@ -39,7 +40,6 @@ import { useOptionalComponent } from '@etherealengine/ecs' import { NO_PROXY, State, getMutableState, getState } from '@etherealengine/hyperflux' -import { EngineState } from '@etherealengine/spatial/src/EngineState' import { addObjectToGroup, removeObjectFromGroup } from '@etherealengine/spatial/src/renderer/components/GroupComponent' import { useEffect, useRef } from 'react' import { @@ -611,7 +611,7 @@ function NewVolumetricComponentReactor() { component.geometry.targets.set(['corto']) if (!getState(AssetLoaderState).cortoLoader) { const loader = new CORTOLoader() - loader.setDecoderPath(getState(EngineState).publicPath + '/loader_decoders/') + loader.setDecoderPath(Engine.instance.store.publicPath + '/loader_decoders/') loader.preload() const assetLoaderState = getMutableState(AssetLoaderState) assetLoaderState.cortoLoader.set(loader) diff --git a/packages/engine/src/scene/components/UVOL1Component.ts b/packages/engine/src/scene/components/UVOL1Component.ts index 8889efe132..2b90f59b8c 100644 --- a/packages/engine/src/scene/components/UVOL1Component.ts +++ b/packages/engine/src/scene/components/UVOL1Component.ts @@ -55,7 +55,6 @@ import { useExecute } from '@etherealengine/ecs/src/SystemFunctions' import { AnimationSystemGroup } from '@etherealengine/ecs/src/SystemGroups' import { getMutableState, getState } from '@etherealengine/hyperflux' import { iOS } from '@etherealengine/spatial/src/common/functions/isMobile' -import { EngineState } from '@etherealengine/spatial/src/EngineState' import { addObjectToGroup, removeObjectFromGroup } from '@etherealengine/spatial/src/renderer/components/GroupComponent' import { RendererComponent } from '@etherealengine/spatial/src/renderer/WebGLRendererSystem' @@ -161,7 +160,7 @@ function UVOL1Reactor() { useEffect(() => { if (!getState(AssetLoaderState).cortoLoader) { const loader = new CORTOLoader() - loader.setDecoderPath(getState(EngineState).publicPath + '/loader_decoders/') + loader.setDecoderPath(Engine.instance.store.publicPath + '/loader_decoders/') loader.preload() const assetLoaderState = getMutableState(AssetLoaderState) assetLoaderState.cortoLoader.set(loader)