Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.

Adding support for client-only build. #8644

Draft
wants to merge 9 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/dev-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: dev-deploy
on:
push:
branches:
[dev]
[exp-update-loading-screen]
jobs:
secrets-gate-run:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -74,8 +74,6 @@ jobs:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }}
PUBLISH_DOCKERHUB: ${{ secrets.PUBLISH_DOCKERHUB }}
- name: Deploy to EKS
run: bash scripts/deploy_builder.sh dev $GITHUB_SHA
- name: Job succeeded
if: ${{ needs.secrets-gate-webhook.outputs.ok == 'enabled' }}
uses: ruby/setup-ruby@v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ export const MediaIconsBox = () => {

const spectating = useHookstate(getMutableState(EngineState).spectating)
const xrState = useHookstate(getMutableState(XRState))
const supportsAR = xrState.supportedSessionModes['immersive-ar'].value
// const supportsAR = xrState.supportedSessionModes['immersive-ar'].value
const supportsAR = false
const xrMode = xrState.sessionMode.value
const supportsVR = xrState.supportedSessionModes['immersive-vr'].value

Expand Down
127 changes: 55 additions & 72 deletions packages/client-core/src/systems/LoadingUISystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ import React, { useEffect } from 'react'
import { Color, CompressedTexture, DoubleSide, Mesh, MeshBasicMaterial, SphereGeometry, Texture, Vector2 } from 'three'

import { AssetLoader } from '@etherealengine/engine/src/assets/classes/AssetLoader'
import createReadableTexture from '@etherealengine/engine/src/assets/functions/createReadableTexture'
import { AppLoadingState, AppLoadingStates } from '@etherealengine/engine/src/common/AppLoadingService'
import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { EngineActions, EngineState } from '@etherealengine/engine/src/ecs/classes/EngineState'
import { EngineState } from '@etherealengine/engine/src/ecs/classes/EngineState'
import { SceneState } from '@etherealengine/engine/src/ecs/classes/Scene'
import {
addComponent,
Expand All @@ -52,9 +51,10 @@ import {
import { XRUIComponent } from '@etherealengine/engine/src/xrui/components/XRUIComponent'
import { createTransitionState } from '@etherealengine/engine/src/xrui/functions/createTransitionState'
import { ObjectFitFunctions } from '@etherealengine/engine/src/xrui/functions/ObjectFitFunctions'
import { defineActionQueue, defineState, getMutableState, getState, useHookstate } from '@etherealengine/hyperflux'
import { defineState, getMutableState, getState, State, useHookstate } from '@etherealengine/hyperflux'
import type { WebLayer3D } from '@etherealengine/xrui'

import { SceneData } from '@etherealengine/common/src/interfaces/SceneInterface'
import { CameraComponent } from '@etherealengine/engine/src/camera/components/CameraComponent'
import { AdminClientSettingsState } from '../admin/services/Setting/ClientSettingService'
import { AppThemeState, getAppTheme } from '../common/services/AppThemeState'
Expand Down Expand Up @@ -86,40 +86,39 @@ const LoadingUISystemState = defineState({
setObjectLayers(mesh, ObjectLayers.UI)

return {
metadataLoaded: false,
ui,
mesh,
transition
}
}
})

const avatarModelChangedQueue = defineActionQueue(EngineActions.avatarModelChanged.matches)
const spectateUserQueue = defineActionQueue(EngineActions.spectateUser.matches)

function LoadingReactor() {
const loadingState = useHookstate(getMutableState(AppLoadingState))
const engineState = useHookstate(getMutableState(EngineState))
const loadingProgress = useHookstate(getMutableState(EngineState).loadingProgress)
const sceneLoaded = useHookstate(getMutableState(EngineState).sceneLoaded)
const userReady = useHookstate(getMutableState(EngineState).userReady)
const state = useHookstate(getMutableState(LoadingUISystemState))
const sceneData = useHookstate(getMutableState(SceneState).sceneData)
const sceneData = useHookstate(getMutableState(SceneState).sceneData) as State<SceneData>
const mesh = state.mesh.value
const metadataLoaded = state.metadataLoaded

/** Handle loading state changes */
useEffect(() => {
const transition = getState(LoadingUISystemState).transition
console.log('metadataLoaded', metadataLoaded.value)
if (loadingState.state.value === AppLoadingStates.SCENE_LOADING && transition.state === 'OUT')
return transition.setState('IN')

if (loadingState.state.value === AppLoadingStates.FAIL && transition.state === 'IN')
return transition.setState('OUT')

if (
loadingState.state.value === AppLoadingStates.SCENE_LOADING &&
transition.state === 'OUT' &&
metadataLoaded.value
) {
transition.setState('IN')
}
if (loadingState.state.value === AppLoadingStates.FAIL && transition.state === 'IN') {
transition.setState('OUT')
}
}, [loadingState.state, metadataLoaded])
loadingState.state.value === AppLoadingStates.SUCCESS &&
transition.state === 'IN' &&
userReady.value &&
sceneLoaded.value
)
return transition.setState('OUT')
}, [loadingState.state, userReady, sceneLoaded])

/** Scene Colors */
function setDefaultPalette() {
Expand All @@ -146,9 +145,7 @@ function LoadingReactor() {
/** Scene data changes */
useEffect(() => {
if (!sceneData.value) return
const envmapURL = sceneData.value.thumbnailUrl
.replace('thumbnail.jpeg', 'envmap.png')
.replace('thumbnail.ktx2', 'envmap.ktx2')
const envmapURL = sceneData.value.thumbnailUrl.split('/').slice(0, -1).join('/') + '/loadingscreen.ktx2'
if (envmapURL && mesh.userData.url !== envmapURL) {
mesh.userData.url = envmapURL
setDefaultPalette()
Expand All @@ -160,20 +157,20 @@ function LoadingReactor() {
(texture: Texture | CompressedTexture) => {
mesh.material.map = texture

const compressedTexture = texture as CompressedTexture
if (compressedTexture.isCompressedTexture) {
try {
createReadableTexture(compressedTexture).then((texture: Texture) => {
setColors(texture)
texture.dispose()
})
} catch (e) {
console.error(e)
setDefaultPalette()
}
} else {
setColors(texture)
}
// const compressedTexture = texture as CompressedTexture
// if (compressedTexture.isCompressedTexture) {
// try {
// createReadableTexture(compressedTexture).then((texture: Texture) => {
// // setColors(texture)
// texture.dispose()
// })
// } catch (e) {
// console.error(e)
// setDefaultPalette()
// }
// } else {
// // setColors(texture)
// }
},
undefined,
(error: ErrorEvent) => {
Expand All @@ -182,20 +179,20 @@ function LoadingReactor() {
}
)
}
}, [sceneData])
}, [sceneData?.thumbnailUrl])

useEffect(() => {
const xrui = getComponent(state.ui.entity.value, XRUIComponent)
const progressBar = xrui.getObjectByName('progress-container') as WebLayer3D | undefined
if (!progressBar) return

if (progressBar.position.lengthSq() <= 0) progressBar.shouldApplyDOMLayout = 'once'
const percentage = engineState.loadingProgress.value
const percentage = loadingProgress.value
const scaleMultiplier = 0.01
const centerOffset = 0.05
progressBar.scale.setX(percentage * scaleMultiplier)
progressBar.position.setX(percentage * scaleMultiplier * centerOffset - centerOffset)
}, [engineState.loadingProgress])
}, [loadingProgress])

return null
}
Expand All @@ -204,25 +201,11 @@ const mainThemeColor = new Color()
const defaultColor = new Color()

const execute = () => {
const { transition, ui, mesh, metadataLoaded } = getState(LoadingUISystemState)
const { transition, ui, mesh } = getState(LoadingUISystemState)
if (!transition) return

const appLoadingState = getState(AppLoadingState)
const engineState = getState(EngineState)

for (const action of spectateUserQueue()) {
if (appLoadingState.state === AppLoadingStates.SUCCESS && engineState.sceneLoaded) transition.setState('OUT')
}

for (const action of avatarModelChangedQueue()) {
if (
(action.entity === Engine.instance.localClientEntity || engineState.spectating) &&
appLoadingState.state === AppLoadingStates.SUCCESS &&
engineState.sceneLoaded
)
transition.setState('OUT')
}

if (transition.state === 'OUT' && transition.alpha === 0) {
removeComponent(ui.entity, ComputedTransformComponent)
return
Expand Down Expand Up @@ -258,26 +241,27 @@ const execute = () => {
// // todo: figure out how to make this work properly for VR #7256
// }

mainThemeColor.set(ui.state.colors.alternate.value)
// mainThemeColor.set(ui.state.colors.alternate.value)

transition.update(engineState.deltaSeconds, (opacity) => {
getMutableState(LoadingSystemState).loadingScreenOpacity.set(opacity)
})

const opacity = getState(LoadingSystemState).loadingScreenOpacity
const ready = opacity > 0

mesh.material.opacity = opacity
mesh.visible = ready

xrui.rootLayer.traverseLayersPreOrder((layer: WebLayer3D) => {
const mat = layer.contentMesh.material as MeshBasicMaterial
mat.opacity = opacity
mat.visible = ready
layer.visible = ready
mat.color.lerpColors(defaultColor, mainThemeColor, engineState.loadingProgress * 0.01)
})
setVisibleComponent(ui.entity, ready)
setVisibleComponent(ui.entity, false)
// const opacity = getState(LoadingSystemState).loadingScreenOpacity
// const ready = opacity > 0

// mesh.material.opacity = opacity
// mesh.visible = ready

// xrui.rootLayer.traverseLayersPreOrder((layer: WebLayer3D) => {
// const mat = layer.contentMesh.material as MeshBasicMaterial
// mat.opacity = opacity
// mat.visible = ready
// layer.visible = ready
// mat.color.lerpColors(defaultColor, mainThemeColor, engineState.loadingProgress * 0.01)
// })
// setVisibleComponent(ui.entity, ready && !getState(XRState).sessionActive)
}

const reactor = () => {
Expand All @@ -298,7 +282,6 @@ const reactor = () => {
// removeEntity(ui.entity)
// mesh.removeFromParent()
// getMutableState(LoadingUISystemState).set({
// metadataLoaded: false,
// ui: null!,
// mesh: null!,
// transition: null!
Expand Down
95 changes: 95 additions & 0 deletions packages/client/client-only-build/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
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 packageRoot from 'app-root-path'
import dotenv from 'dotenv'
import fs from 'fs'
import path from 'path'
import { defineConfig, UserConfig } from 'vite'

export default defineConfig(async () => {
dotenv.config({
path: packageRoot.path + '/.env.local'
})

const isDevOrLocal = process.env.APP_ENV === 'development' || process.env.VITE_LOCAL_BUILD === 'true'

const base = `https://${process.env['STATIC_BUILD_HOST'] ?? 'localhost:3000'}/`

const returned = {
server: {
cors: isDevOrLocal ? false : true,
hmr:
process.env.VITE_HMR === 'true'
? {
port: process.env['VITE_APP_PORT'],
host: process.env['VITE_APP_HOST'],
overlay: false
}
: false,
host: process.env['VITE_APP_HOST'],
port: process.env['VITE_APP_PORT'],
headers: {
'Origin-Agent-Cluster': '?1'
},
...(isDevOrLocal
? {
https: {
key: fs.readFileSync(path.join(packageRoot.path, 'certs/key.pem')),
cert: fs.readFileSync(path.join(packageRoot.path, 'certs/cert.pem'))
}
}
: {})
},
base,
optimizeDeps: {
entries: ['./src/main.tsx'],
exclude: ['@etherealengine/volumetric'],
esbuildOptions: {
target: 'es2020'
}
},
plugins: [],
build: {
target: 'esnext',
sourcemap: 'inline',
minify: 'esbuild',
dynamicImportVarsOptions: {
warnOnError: true
},
rollupOptions: {
external: ['dotenv-flow'],
output: {
dir: 'dist',
format: 'es', // 'commonjs' | 'esm' | 'module' | 'systemjs'
// ignore files under 1mb
experimentalMinChunkSize: 1000000
}
}
}
} as UserConfig

return returned
})
4 changes: 2 additions & 2 deletions packages/engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
},
"version": "1.4.0",
"dependencies": {
"@behave-graph/core": "https://gitpkg.now.sh/EtherealEngine/behave-graph/packages/core?dev",
"@behave-graph/scene": "https://gitpkg.now.sh/EtherealEngine/behave-graph/packages/scene?dev",
"@behave-graph/core": "https://gitpkg.now.sh/EtherealEngine/behave-graph/packages/core?ee-1.4.0-LTS",
"@behave-graph/scene": "https://gitpkg.now.sh/EtherealEngine/behave-graph/packages/scene?ee-1.4.0-LTS",
"@dimforge/rapier3d-compat": "0.11.1",
"@etherealengine/common": "^1.4.0",
"@etherealengine/hyperflux": "^1.4.0",
Expand Down
7 changes: 4 additions & 3 deletions packages/engine/src/avatar/functions/avatarFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ import {
Vector3
} from 'three'

import { dispatchAction, getMutableState, getState } from '@etherealengine/hyperflux'
import { getMutableState, getState } from '@etherealengine/hyperflux'

import { AssetLoader } from '../../assets/classes/AssetLoader'
import { isClient } from '../../common/functions/getEnvironment'
import { iOS } from '../../common/functions/isMobile'
import { EngineActions, EngineState } from '../../ecs/classes/EngineState'
import { EngineState } from '../../ecs/classes/EngineState'
import { Entity } from '../../ecs/classes/Entity'
import {
addComponent,
Expand All @@ -64,6 +64,7 @@ import { AnimationState } from '../AnimationManager'
// import { retargetSkeleton, syncModelSkeletons } from '../animation/retargetSkeleton'
import config from '@etherealengine/common/src/config'
import { GLTF } from '../../assets/loaders/gltf/GLTFLoader'
import { Engine } from '../../ecs/classes/Engine'
import avatarBoneMatching, {
BoneNames,
findSkinnedMeshes,
Expand Down Expand Up @@ -148,7 +149,7 @@ export const loadAvatarForUser = async (
})
}

dispatchAction(EngineActions.avatarModelChanged({ entity }))
if (entity === Engine.instance.localClientEntity) getMutableState(EngineState).userReady.set(true)
}

export const setupAvatarForUser = (entity: Entity, model: VRM) => {
Expand Down
Loading