Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework Studio Scene Loading, Other scene cleanup #9349

Merged
merged 8 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions packages/client-core/src/admin/services/SceneService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ Ethereal Engine. All Rights Reserved.
*/

import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { SceneDataType, SceneMetadataType, scenePath } from '@etherealengine/engine/src/schemas/projects/scene.schema'
import {
SceneDataType,
SceneID,
SceneMetadataType,
scenePath
} from '@etherealengine/engine/src/schemas/projects/scene.schema'
import { defineState, getMutableState } from '@etherealengine/hyperflux'

export const SCENE_PAGE_LIMIT = 100
Expand Down Expand Up @@ -57,7 +62,7 @@ export const AdminSceneService = {
lastFetched: Date.now()
})
},
fetchAdminScene: async (sceneKey: string) => {
fetchAdminScene: async (sceneKey: SceneID) => {
const scene = await Engine.instance.api
.service(scenePath)
.get(null, { query: { sceneKey: sceneKey, metadataOnly: false } })
Expand Down
20 changes: 10 additions & 10 deletions packages/client-core/src/components/Debug/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ import { System, SystemDefinitions, SystemUUID } from '@etherealengine/engine/sr
import { RendererState } from '@etherealengine/engine/src/renderer/RendererState'
import { NameComponent } from '@etherealengine/engine/src/scene/components/NameComponent'
import { UUIDComponent } from '@etherealengine/engine/src/scene/components/UUIDComponent'
import { NO_PROXY, getMutableState, useHookstate } from '@etherealengine/hyperflux'
import { NO_PROXY, getMutableState, getState, useHookstate } from '@etherealengine/hyperflux'
import Icon from '@etherealengine/ui/src/primitives/mui/Icon'

import { SceneState } from '@etherealengine/engine/src/ecs/classes/Scene'
import ActionsPanel from './ActionsPanel'
import { StatsPanel } from './StatsPanel'
import styles from './styles.module.scss'
Expand Down Expand Up @@ -126,15 +127,14 @@ export const Debug = ({ showingStateRef }: { showingStateRef: React.MutableRefOb

const renderEntityTreeRoots = () => {
return {
...Object.keys(EntityTreeComponent.roots.value).reduce(
(r, child, i) =>
Object.assign(r, {
[`${i} - ${
getComponent(child as any as Entity, NameComponent) ?? getComponent(child as any as Entity, UUIDComponent)
}`]: renderEntityTree(child as any as Entity)
}),
{}
)
...Object.values(getState(SceneState).scenes).map((scene, i) => {
const root = scene.snapshots[scene.index].data.root
const entity = UUIDComponent.entitiesByUUID[root]
return {
[`${i} - ${getComponent(entity, NameComponent) ?? getComponent(entity, UUIDComponent)}`]:
renderEntityTree(entity)
}
})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,14 @@ export const useLoadLocation = (props: { locationName: string }) => {
*/
useEffect(() => {
if (!locationState.currentLocation.location.sceneId.value) return
const scenePath = locationState.currentLocation.location.sceneId.value.split('/')
const project = scenePath[scenePath.length - 2]
const scene = scenePath[scenePath.length - 1].replace('.scene.json', '')
return SceneServices.setCurrentScene(project, scene)
const scenePath = locationState.currentLocation.location.sceneId.value
return SceneServices.setCurrentScene(scenePath)
}, [locationState.currentLocation.location.sceneId])
}

export const useLoadScene = (props: { projectName: string; sceneName: string }) => {
useEffect(() => {
LocationState.setLocationName(`${props.projectName}/${props.sceneName}`)
LocationState.setLocationName(`projects/${props.projectName}/${props.sceneName}.scene.json`)
loadSceneJsonOffline(props.projectName, props.sceneName)
}, [])
}
13 changes: 9 additions & 4 deletions packages/client-core/src/world/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,22 @@ import config from '@etherealengine/common/src/config'
import { parseStorageProviderURLs } from '@etherealengine/engine/src/common/functions/parseSceneJSON'
import { SceneState } from '@etherealengine/engine/src/ecs/classes/Scene'
import { SceneID, SceneJsonType } from '@etherealengine/engine/src/schemas/projects/scene.schema'
import { getMutableState } from '@etherealengine/hyperflux'

const fileServer = config.client.fileServer

export const loadSceneJsonOffline = async (projectName, sceneName) => {
const sceneID = `${projectName}/${sceneName}` as SceneID
const sceneData = (await (await fetch(`${fileServer}/projects/${sceneID}.scene.json`)).json()) as SceneJsonType
const hasKTX2 = await fetch(`${fileServer}/projects/${sceneID}.thumbnail.ktx2`).then((res) => res.ok)
const sceneID = `projects/${projectName}/${sceneName}.scene.json` as SceneID
const sceneData = (await (
await fetch(`${fileServer}/projects/${projectName}/${sceneName}.scene.json`)
).json()) as SceneJsonType
const hasKTX2 = await fetch(`${fileServer}/projects/${projectName}/${sceneName}.thumbnail.ktx2`).then((res) => res.ok)
SceneState.loadScene(sceneID, {
scene: parseStorageProviderURLs(sceneData),
name: sceneName,
thumbnailUrl: `${fileServer}/projects/${sceneID}.thumbnail.${hasKTX2 ? 'ktx2' : 'jpeg'}`,
scenePath: sceneID,
thumbnailUrl: `${fileServer}/projects/${projectName}/${sceneName}.thumbnail.${hasKTX2 ? 'ktx2' : 'jpeg'}`,
project: projectName
})
getMutableState(SceneState).activeScene.set(sceneID)
}
23 changes: 18 additions & 5 deletions packages/client/src/pages/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,29 @@ import { PopupMenuInline } from '@etherealengine/client-core/src/user/components
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 { ProjectPage } from '@etherealengine/editor/src/pages/ProjectPage'
import { EditorState } from '@etherealengine/editor/src/services/EditorServices'
import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { scenePath } from '@etherealengine/engine/src/schemas/projects/scene.schema'
import { getMutableState } from '@etherealengine/hyperflux'

const RedirectStudio = () => {
const { projectName, sceneName } = useParams()
const navigate = useNavigate()

useEffect(() => {
navigate('/studio/' + projectName + '?scene=' + sceneName)
})
Engine.instance.api
.service(scenePath)
.get(null, { query: { project: projectName, name: sceneName, metadataOnly: true } })
.then((result) => {
getMutableState(EditorState).merge({
sceneName,
projectName,
sceneID: result.scenePath
})
navigate(`/studio?scenePath=${result.scenePath}`)
})
}, [])

return <></>
}

Expand All @@ -56,8 +70,7 @@ const EditorRouter = () => {
<PopupMenuInline />
<Routes>
<Route path=":projectName/:sceneName" element={<RedirectStudio />} />
<Route path=":projectName" element={<EditorPage />} />
<Route path="*" element={<ProjectPage />} />
<Route path="*" element={<EditorPage />} />
</Routes>
</Suspense>
)
Expand Down
77 changes: 29 additions & 48 deletions packages/editor/src/components/EditorContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,13 @@ import { getMutableState, getState, useHookstate } from '@etherealengine/hyperfl

import Dialog from '@mui/material/Dialog'

import { SceneState } from '@etherealengine/engine/src/ecs/classes/Scene'
import { SceneServices, SceneState } from '@etherealengine/engine/src/ecs/classes/Scene'
import { useQuery } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { SceneAssetPendingTagComponent } from '@etherealengine/engine/src/scene/components/SceneAssetPendingTagComponent'
import { SceneID } from '@etherealengine/engine/src/schemas/projects/scene.schema'
import CircularProgress from '@etherealengine/ui/src/primitives/mui/CircularProgress'
import { t } from 'i18next'
import { inputFileWithAddToScene } from '../functions/assetFunctions'
import { getScene, onNewScene, saveScene } from '../functions/sceneFunctions'
import { onNewScene, saveScene } from '../functions/sceneFunctions'
import { takeScreenshot } from '../functions/takeScreenshot'
import { uploadSceneBakeToServer } from '../functions/uploadEnvMapBake'
import { cmdOrCtrlString } from '../functions/utils'
Expand Down Expand Up @@ -123,23 +122,6 @@ const SceneLoadingProgress = () => {
)
}

const loadScene = async (sceneName: string) => {
const { projectName } = getState(EditorState)
try {
if (!projectName) {
return
}
const project = await getScene(projectName, sceneName, false)

if (!project.scene) {
return
}
SceneState.loadScene(`${projectName}/${sceneName}` as SceneID, project)
} catch (error) {
logger.error(error)
}
}

/**
* Scene Event Handlers
*/
Expand All @@ -164,9 +146,20 @@ const onCloseProject = () => {
const editorState = getMutableState(EditorState)
editorState.sceneModified.set(false)
editorState.projectName.set(null)
editorState.sceneID.set(null)
editorState.sceneName.set(null)
SceneState.unloadScene(getState(SceneState).activeScene!)
RouterState.navigate('/studio')

const parsed = new URL(window.location.href)
const query = parsed.searchParams

query.delete('project')
query.delete('scenePath')

parsed.search = query.toString()
if (typeof history.pushState !== 'undefined') {
window.history.replaceState({}, '', parsed.toString())
}
}

const onSaveAs = async () => {
Expand Down Expand Up @@ -370,11 +363,11 @@ const panels = [
* EditorContainer class used for creating container for Editor
*/
const EditorContainer = () => {
const editorState = useHookstate(getMutableState(EditorState))
const sceneName = editorState.sceneName
const { sceneName, projectName, sceneID, sceneModified } = useHookstate(getMutableState(EditorState))
const sceneLoaded = useHookstate(getMutableState(EngineState)).sceneLoaded
const activeScene = useHookstate(getMutableState(SceneState).activeScene)

const sceneLoading = sceneName.value && !sceneLoaded.value
const sceneLoading = sceneID.value && !sceneLoaded.value

const errorState = useHookstate(getMutableState(EditorErrorState).error)

Expand Down Expand Up @@ -409,17 +402,10 @@ const EditorContainer = () => {
}
})

useEffect(() => {
const sceneInParams = new URL(window.location.href).searchParams.get('scene')
if (sceneInParams) {
editorState.sceneName.set(sceneInParams)
}
}, [])

useHotkeys(`${cmdOrCtrlString}+s`, () => onSaveScene() as any)

useEffect(() => {
if (!editorState.sceneModified.value) return
if (!sceneModified.value) return
const onBeforeUnload = (e) => {
alert('You have unsaved changes. Please save before leaving.')
e.preventDefault()
Expand All @@ -431,24 +417,19 @@ const EditorContainer = () => {
return () => {
window.removeEventListener('beforeunload', onBeforeUnload)
}
}, [editorState.sceneModified])
}, [sceneModified])

useEffect(() => {
if (sceneName.value) {
logger.info(`Loading scene ${sceneName.value}`)
loadScene(sceneName.value)
if (!sceneID.value) return
return SceneServices.setCurrentScene(sceneID.value)
}, [sceneID])

const parsed = new URL(window.location.href)
const query = parsed.searchParams

query.set('scene', sceneName.value)

parsed.search = query.toString()
if (typeof history.pushState !== 'undefined') {
window.history.replaceState({}, '', parsed.toString())
}
}
}, [sceneName])
useEffect(() => {
if (!activeScene.value) return
const scene = getState(SceneState).scenes[activeScene.value]
sceneName.set(scene.metadata.name)
projectName.set(scene.metadata.project)
}, [activeScene])

useEffect(() => {
if (!dockPanelRef.current) return
Expand All @@ -467,7 +448,7 @@ const EditorContainer = () => {
<div
id="editor-container"
className={styles.editorContainer}
style={sceneName.value ? { background: 'transparent' } : {}}
style={sceneID.value ? { background: 'transparent' } : {}}
>
<DndWrapper id="editor-container">
<DragLayer />
Expand Down
12 changes: 5 additions & 7 deletions packages/editor/src/components/assets/ScenesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ import styles from './styles.module.scss'

const logger = multiLogger.child({ component: 'editor:ScenesPanel' })

const editorState = getMutableState(EditorState)

/**
* Displays the scenes that exist in the current project.
*/
export default function ScenesPanel({ loadScene, newScene }) {
export default function ScenesPanel() {
const { t } = useTranslation()
const [scenes, setScenes] = useState<SceneDataType[]>([])
const [isContextMenuOpen, setContextMenuOpen] = useState(false)
Expand Down Expand Up @@ -89,13 +87,13 @@ export default function ScenesPanel({ loadScene, newScene }) {
}, [editorState.sceneName])

const onCreateScene = async () => {
await newScene()
await onNewScene()
fetchItems()
}

const onClickExisting = async (e, scene) => {
const onClickExisting = async (e, scene: SceneDataType) => {
e.preventDefault()
loadScene(scene.name)
setSceneInState(scene.scenePath)
fetchItems()
}

Expand Down Expand Up @@ -263,5 +261,5 @@ export const ScenePanelTab: TabData = {
<PanelTitle>Scenes</PanelTitle>
</PanelDragContainer>
),
content: <ScenesPanel newScene={onNewScene} loadScene={setSceneInState} />
content: <ScenesPanel />
}
14 changes: 12 additions & 2 deletions packages/editor/src/components/projects/ProjectsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { useTranslation } from 'react-i18next'

import ProjectDrawer from '@etherealengine/client-core/src/admin/components/Project/ProjectDrawer'
import { ProjectService, ProjectState } from '@etherealengine/client-core/src/common/services/ProjectService'
import { RouterState } from '@etherealengine/client-core/src/common/services/RouterService'
import { AuthState } from '@etherealengine/client-core/src/user/services/AuthService'
import multiLogger from '@etherealengine/engine/src/common/functions/logger'
import { getMutableState, useHookstate } from '@etherealengine/hyperflux'
Expand Down Expand Up @@ -66,7 +65,9 @@ import { userHasAccess } from '@etherealengine/client-core/src/user/userHasAcces
import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { projectPath, ProjectType } from '@etherealengine/engine/src/schemas/projects/project.schema'
import { InviteCode } from '@etherealengine/engine/src/schemas/user/user.schema'
import { useNavigate } from 'react-router-dom'
import { getProjects } from '../../functions/projectFunctions'
import { EditorState } from '../../services/EditorServices'
import { Button, MediumButton } from '../inputs/Button'
import { CreateProjectDialog } from './CreateProjectDialog'
import { DeleteDialog } from './DeleteDialog'
Expand Down Expand Up @@ -183,6 +184,7 @@ const ProjectsPage = () => {
const projectDrawerOpen = useHookstate(false)
const changeDestination = useHookstate(false)

const navigate = useNavigate()
const hasWriteAccess =
activeProject.value?.hasWriteAccess || (userHasAccess('admin:admin') && userHasAccess('projects:write'))

Expand Down Expand Up @@ -275,7 +277,15 @@ const ProjectsPage = () => {
const onClickExisting = (event, project) => {
event.preventDefault()
if (!isInstalled(project)) return
RouterState.navigate(`/studio/${project.name}`)
navigate(`/studio?project=${project.name}`)
getMutableState(EditorState).projectName.set(project.name)
const parsed = new URL(window.location.href)
const query = parsed.searchParams
query.set('project', project.name)
parsed.search = query.toString()
if (typeof history.pushState !== 'undefined') {
window.history.replaceState({}, '', parsed.toString())
}
}

const onCreateProject = async (name) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,20 @@ import { getMutableState, getState } from '@etherealengine/hyperflux'

import { EngineState } from '@etherealengine/engine/src/ecs/classes/EngineState'
import { PresentationSystemGroup } from '@etherealengine/engine/src/ecs/functions/EngineFunctions'
import { SceneID } from '@etherealengine/engine/src/schemas/projects/scene.schema'
import { EditorState } from '../../services/EditorServices'
import { EditorActiveInstanceState } from './EditorActiveInstanceService'

let accumulator = 0

const execute = () => {
const editorState = getState(EditorState)
if (!editorState.projectName || !editorState.sceneName) return
if (!editorState.sceneID) return

accumulator += getState(EngineState).deltaSeconds

if (accumulator > 5) {
accumulator = 0
const sceneId = `${editorState.projectName}/${editorState.sceneName}` as SceneID
EditorActiveInstanceState.getActiveInstances(sceneId)
EditorActiveInstanceState.getActiveInstances(editorState.sceneID)
}
}

Expand Down