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

Commit

Permalink
Event Sourcing (#8119)
Browse files Browse the repository at this point in the history
* wip

* Merge branch 'dev' of https://github.com/EtherealEngine/etherealengine into event-sourced-hyperflux

* mix err

* Merge branch 'dev' into event-sourced-hyperflux

* Revert "Merge branch 'dev' into event-sourced-hyperflux"

This reverts commit ba5a1a1.

* Wip

* Cleanup avatar files

* finish implementing and ts fixes

* licence

* fix bugs and circlular dependencies

* license

* test fix

* default project testing and tsc error checking

* remove unnecessary action

* fix test

* fix branch build with new check errors

---------

Co-authored-by: Gheric Speiginer <gheric.speiginer@gmail.com>
  • Loading branch information
HexaField and speigg authored Jul 6, 2023
1 parent 5779909 commit 83660c6
Show file tree
Hide file tree
Showing 78 changed files with 949 additions and 709 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/branch-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ jobs:
NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: npm install --production=false --loglevel notice --legacy-peer-deps
- run: npm run lint
- run: npm run check-errors
timeout-minutes: 20
- run: npm run dev-docker
- run: npm run dev-reinit
- run: npm run check-errors
timeout-minutes: 20
- run: npm run build-client
- run: npm run test
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"scripts": {
"build-client": "cd packages/client && npm run build",
"check": "npm run lint && npm run check-errors && npm run test && npm run test:projects && npm run build-client",
"check-errors": "lerna run check-errors",
"check-errors": "lerna run --scope '@etherealengine/*' check-errors && lerna run --ignore '@etherealengine/*' check-errors",
"clean-node-modules": "npx rimraf node_modules && npx rimraf package-lock.json && npx lerna exec npx rimraf node_modules && npx lerna exec npx rimraf package-lock.json",
"create-root-package-json": "cross-env ts-node --swc scripts/create-root-package-json",
"depcheck": "lerna exec --no-bail --stream -- depcheck",
Expand Down Expand Up @@ -72,9 +72,8 @@
"publish": "lerna publish from-package --yes --registry https://registry.npmjs.org",
"publish-npm": "lerna publish from-package --yes --no-verify-access --ignore-scripts --registry https://registry.npmjs.org",
"publish-github": "lerna publish from-package --yes --no-verify-access --ignore-scripts --registry https://npm.pkg.github.com",
"test": "cross-env TEST=true lerna run test",
"test": "cross-env TEST=true lerna run --scope '@etherealengine/*' test && lerna run --ignore '@etherealengine/*' test",
"test-e2e": "ts-node --swc scripts/run_e2e_tests.ts",
"test:projects": "cross-env TEST=true lerna run test:projects",
"test:ci": "cpy --no-overwrite --rename=.env.local '.env.local.default' . && cross-env CI=true npm run test",
"validate": "npm run lint && lerna run validate",
"version-increment": "lerna version --conventional-commits --yes",
Expand Down
7 changes: 3 additions & 4 deletions packages/client-core/src/admin/components/Avatars/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'

import ConfirmDialog from '@etherealengine/client-core/src/common/components/ConfirmDialog'
import { AnimationSystem } from '@etherealengine/engine/src/avatar/AnimationSystem'
import { AvatarAnimationSystem } from '@etherealengine/engine/src/avatar/AvatarAnimationSystem'
import { AvatarSpawnSystem } from '@etherealengine/engine/src/avatar/AvatarSpawnSystem'
import { AnimationSystem } from '@etherealengine/engine/src/avatar/systems/AnimationSystem'
import { AvatarAnimationSystem } from '@etherealengine/engine/src/avatar/systems/AvatarAnimationSystem'
import { DebugRendererSystem } from '@etherealengine/engine/src/debug/systems/DebugRendererSystem'
import { AnimationSystemGroup, PresentationSystemGroup } from '@etherealengine/engine/src/ecs/functions/EngineFunctions'
import { useSystem, useSystems } from '@etherealengine/engine/src/ecs/functions/SystemFunctions'
Expand All @@ -56,7 +55,7 @@ const Avatar = () => {
const [selectedAvatarIds, setSelectedAvatarIds] = useState(() => new Set<string>())

/** Avatar / Animation */
useSystems([AnimationSystem, AvatarSpawnSystem, AvatarAnimationSystem], {
useSystems([AnimationSystem, AvatarAnimationSystem], {
with: AnimationSystemGroup
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import classNames from 'classnames'
import React from 'react'
import { useTranslation } from 'react-i18next'

import { getAvatarURLForUser } from '@etherealengine/client-core/src/user/components/UserMenu/util'
import { PeerID } from '@etherealengine/common/src/interfaces/PeerID'
import Icon from '@etherealengine/ui/src/primitives/mui/Icon'
import IconButton from '@etherealengine/ui/src/primitives/mui/IconButton'
Expand All @@ -46,7 +45,6 @@ const { t } = useTranslation()

const ConferenceModeParticipant = ({ peerID, type }: Props): JSX.Element => {
const {
userId,
volume,
isScreen,
username,
Expand All @@ -55,7 +53,7 @@ const ConferenceModeParticipant = ({ peerID, type }: Props): JSX.Element => {
videoStream,
audioStream,
enableGlobalMute,
userAvatarDetails,
avatarThumbnail,
videoStreamPaused,
audioStreamPaused,
videoProducerPaused,
Expand Down Expand Up @@ -87,12 +85,7 @@ const ConferenceModeParticipant = ({ peerID, type }: Props): JSX.Element => {
})}
>
{(videoStream == null || videoStreamPaused || videoProducerPaused || videoProducerGlobalMute) && (
<img
src={getAvatarURLForUser(userAvatarDetails, isSelf ? selfUser?.id : userId)}
alt=""
crossOrigin="anonymous"
draggable={false}
/>
<img src={avatarThumbnail} alt="" crossOrigin="anonymous" draggable={false} />
)}
<span key={peerID + '-video-container'} id={peerID + '-video-container'} />
</div>
Expand Down
17 changes: 4 additions & 13 deletions packages/client-core/src/components/InstanceChat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { Close as CloseIcon, Message as MessageIcon } from '@mui/icons-material'
import Fab from '@mui/material/Fab'

import { AppAction } from '../../common/services/AppService'
import { getAvatarURLForUser } from '../../user/components/UserMenu/util'
import { getUserAvatarThumbnail } from '../../user/functions/useUserAvatarThumbnail'
import { useShelfStyles } from '../Shelves/useShelfStyles'
import defaultStyles from './index.module.scss'
import styles from './index.module.scss'
Expand Down Expand Up @@ -347,24 +347,15 @@ export const InstanceChat = ({
<p className={styles.text}>{message.text}</p>
</div>
{index !== 0 && messages[index - 1] && messages[index - 1].isNotification ? (
<Avatar
src={getAvatarURLForUser(userAvatarDetails, message.senderId)}
className={styles.avatar}
/>
<Avatar src={getUserAvatarThumbnail(message.senderId)} className={styles.avatar} />
) : (
messages[index - 1] &&
message.senderId !== messages[index - 1].senderId && (
<Avatar
src={getAvatarURLForUser(userAvatarDetails, message.senderId)}
className={styles.avatar}
/>
<Avatar src={getUserAvatarThumbnail(message.senderId)} className={styles.avatar} />
)
)}
{index === 0 && (
<Avatar
src={getAvatarURLForUser(userAvatarDetails, message.senderId)}
className={styles.avatar}
/>
<Avatar src={getUserAvatarThumbnail(message.senderId)} className={styles.avatar} />
)}
</div>
</div>
Expand Down
36 changes: 9 additions & 27 deletions packages/client-core/src/components/UserMediaWindow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import {
toggleScreenshareVideoPaused,
toggleWebcamPaused
} from '@etherealengine/client-core/src/transports/SocketWebRTCClientFunctions'
import { getAvatarURLForUser } from '@etherealengine/client-core/src/user/components/UserMenu/util'
import { AuthState } from '@etherealengine/client-core/src/user/services/AuthService'
import { PeerID } from '@etherealengine/common/src/interfaces/PeerID'
import { UserId } from '@etherealengine/common/src/interfaces/UserId'
Expand All @@ -59,6 +58,8 @@ import Tooltip from '@etherealengine/ui/src/primitives/mui/Tooltip'
import { MediaStreamState } from '../../transports/MediaStreams'
import { PeerMediaChannelState, PeerMediaStreamInterface } from '../../transports/PeerMediaChannelState'
import { ConsumerExtension, SocketWebRTCClientNetwork } from '../../transports/SocketWebRTCClientFunctions'
import { useUserAvatarThumbnail } from '../../user/functions/useUserAvatarThumbnail'
import { AvatarState } from '../../user/services/AvatarService'
import Draggable from './Draggable'
import styles from './index.module.scss'

Expand Down Expand Up @@ -116,10 +117,7 @@ export const useUserMediaWindowHook = ({ peerID, type }: Props) => {
peerID === 'self'
const volume = isSelf ? audioState.microphoneGain.value : _volume.value
const isScreen = type === 'screen'
const userId =
mediaNetwork && mediaNetwork.peers && mediaNetwork.peers.get(peerID)
? mediaNetwork.peers.get(peerID!)?.userId
: undefined
const userId = isSelf ? selfUser?.id : mediaNetwork?.peers?.get(peerID!)?.userId

const mediaStreamState = useHookstate(getMutableState(MediaStreamState))
const mediaSettingState = useHookstate(getMutableState(MediaSettingsState))
Expand Down Expand Up @@ -324,7 +322,7 @@ export const useUserMediaWindowHook = ({ peerID, type }: Props) => {

const username = getUsername()

const userAvatarDetails = useHookstate(getMutableState(WorldState).userAvatarDetails)
const avatarThumbnail = useUserAvatarThumbnail(userId)

const handleVisibilityChange = () => {
if (document.hidden) {
Expand Down Expand Up @@ -366,7 +364,6 @@ export const useUserMediaWindowHook = ({ peerID, type }: Props) => {
}, [])

return {
userId,
isPiP: isPiP.value,
volume,
isScreen,
Expand All @@ -376,7 +373,7 @@ export const useUserMediaWindowHook = ({ peerID, type }: Props) => {
videoStream,
audioStream,
enableGlobalMute,
userAvatarDetails,
avatarThumbnail,
videoStreamPaused,
audioStreamPaused,
videoProducerPaused,
Expand All @@ -396,7 +393,6 @@ export const useUserMediaWindowHook = ({ peerID, type }: Props) => {

export const UserMediaWindow = ({ peerID, type }: Props): JSX.Element => {
const {
userId,
isPiP,
volume,
isScreen,
Expand All @@ -406,7 +402,7 @@ export const UserMediaWindow = ({ peerID, type }: Props): JSX.Element => {
videoStream,
audioStream,
enableGlobalMute,
userAvatarDetails,
avatarThumbnail,
videoStreamPaused,
audioStreamPaused,
videoProducerPaused,
Expand Down Expand Up @@ -498,14 +494,7 @@ export const UserMediaWindow = ({ peerID, type }: Props): JSX.Element => {
videoStreamPaused ||
videoProducerPaused ||
videoProducerGlobalMute ||
!videoDisplayReady) && (
<img
src={getAvatarURLForUser(userAvatarDetails, isSelf ? selfUser?.id : userId)}
alt=""
crossOrigin="anonymous"
draggable={false}
/>
)}
!videoDisplayReady) && <img src={avatarThumbnail} alt="" crossOrigin="anonymous" draggable={false} />}
<span key={peerID + '-' + type + '-video-container'} id={peerID + '-' + type + '-video-container'} />
</div>
<span key={peerID + '-' + type + '-audio-container'} id={peerID + '-' + type + '-audio-container'} />
Expand Down Expand Up @@ -615,7 +604,6 @@ export const UserMediaWindow = ({ peerID, type }: Props): JSX.Element => {

export const UserMediaWindowWidget = ({ peerID, type }: Props): JSX.Element => {
const {
userId,
volume,
isScreen,
username,
Expand All @@ -624,7 +612,7 @@ export const UserMediaWindowWidget = ({ peerID, type }: Props): JSX.Element => {
videoStream,
audioStream,
enableGlobalMute,
userAvatarDetails,
avatarThumbnail,
videoStreamPaused,
audioStreamPaused,
videoProducerPaused,
Expand Down Expand Up @@ -674,13 +662,7 @@ export const UserMediaWindowWidget = ({ peerID, type }: Props): JSX.Element => {
xr-layer="true"
>
{videoStream == null || videoStreamPaused || videoProducerPaused || videoProducerGlobalMute ? (
<img
src={getAvatarURLForUser(userAvatarDetails, isSelf ? selfUser?.id : userId)}
alt=""
crossOrigin="anonymous"
draggable={false}
xr-layer="true"
/>
<img src={avatarThumbnail} alt="" crossOrigin="anonymous" draggable={false} xr-layer="true" />
) : (
<video
xr-layer="true"
Expand Down
12 changes: 3 additions & 9 deletions packages/client-core/src/components/World/EngineHooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { PeerID } from '@etherealengine/common/src/interfaces/PeerID'
import { UserId } from '@etherealengine/common/src/interfaces/UserId'
import multiLogger from '@etherealengine/common/src/logger'
import { getSearchParamFromURL } from '@etherealengine/common/src/utils/getSearchParamFromURL'
import { getRandomSpawnPoint, getSpawnPoint } from '@etherealengine/engine/src/avatar/AvatarSpawnSystem'
import { getRandomSpawnPoint, getSpawnPoint } from '@etherealengine/engine/src/avatar/functions/getSpawnPoint'
import { teleportAvatar } from '@etherealengine/engine/src/avatar/functions/moveAvatar'
import {
AppLoadingAction,
Expand Down Expand Up @@ -88,10 +88,7 @@ const fetchMissingAvatar = async (user, avatarSpawnPose) => {
if (avatar && avatar.modelResource?.url)
spawnLocalAvatarInWorld({
avatarSpawnPose,
avatarDetail: {
avatarURL: avatar.modelResource?.url || '',
thumbnailURL: avatar.thumbnailResource?.url || ''
},
avatarID: avatar.id,
name: user.name.value
})
else
Expand Down Expand Up @@ -136,10 +133,7 @@ export const useLocationSpawnAvatar = (spectate = false) => {
if (avatarDetails.modelResource?.url)
spawnLocalAvatarInWorld({
avatarSpawnPose,
avatarDetail: {
avatarURL: avatarDetails.modelResource?.url || '',
thumbnailURL: avatarDetails.thumbnailResource?.url || ''
},
avatarID: user.avatar.id.value,
name: user.name.value
})
else fetchMissingAvatar(user, avatarSpawnPose)
Expand Down
5 changes: 3 additions & 2 deletions packages/client-core/src/media/webcam/WebcamInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { useEffect } from 'react'
import { isDev } from '@etherealengine/common/src/config'
import { createWorkerFromCrossOriginURL } from '@etherealengine/common/src/utils/createWorkerFromCrossOriginURL'
import { AvatarRigComponent } from '@etherealengine/engine/src/avatar/components/AvatarAnimationComponent'
import { AvatarNetworkAction } from '@etherealengine/engine/src/avatar/state/AvatarNetworkState'
import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity'
import {
Expand Down Expand Up @@ -281,11 +282,11 @@ const setAvatarExpression = (entity: Entity): void => {
}
}
const webcamQuery = defineQuery([GroupComponent, AvatarRigComponent, WebcamInputComponent])
const avatarSpawnQueue = defineActionQueue(WorldNetworkAction.spawnAvatar.matches)
const avatarSpawnQueue = defineActionQueue(AvatarNetworkAction.spawn.matches)

const execute = () => {
for (const action of avatarSpawnQueue()) {
const entity = UUIDComponent.entitiesByUUID[action.uuid]
const entity = UUIDComponent.entitiesByUUID[action.entityUUID]
setComponent(entity, WebcamInputComponent)
}
for (const entity of webcamQuery()) setAvatarExpression(entity)
Expand Down
67 changes: 36 additions & 31 deletions packages/client-core/src/recording/RecordingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ import { defineSystem } from '@etherealengine/engine/src/ecs/functions/SystemFun
import { mocapDataChannelType } from '@etherealengine/engine/src/mocap/MotionCaptureSystem'
import { webcamVideoDataChannelType } from '@etherealengine/engine/src/networking/NetworkState'
import { PhysicsSerialization } from '@etherealengine/engine/src/physics/PhysicsSerialization'
import { defineActionQueue, defineState, getMutableState, getState } from '@etherealengine/hyperflux'
import { defineState, getMutableState, getState, receiveActions } from '@etherealengine/hyperflux'

import { NotificationService } from '../common/services/NotificationService'

export const RecordingState = defineState({
name: 'RecordingState',
name: 'ee.RecordingState',

initial: {
started: false,
recordingID: null as string | null,
Expand All @@ -46,7 +47,36 @@ export const RecordingState = defineState({
},
recordings: [] as RecordingResult[],
playback: null as string | null
}
},

receptors: [
[
ECSRecordingActions.startRecording,
(state, action) => {
state.started.set(true)
}
],
[
ECSRecordingActions.recordingStarted,
(state, action) => {
state.started.set(true)
state.recordingID.set(action.recordingID)
}
],
[
ECSRecordingActions.stopRecording,
(state, action) => {
state.started.set(false)
state.recordingID.set(null)
}
],
[
ECSRecordingActions.playbackChanged,
(state, action) => {
state.playback.set(action.playing ? action.recordingID : null)
}
]
]
})

export const RecordingFunctions = {
Expand Down Expand Up @@ -93,34 +123,9 @@ export const RecordingFunctions = {
}
}

const startRecordingQueue = defineActionQueue(ECSRecordingActions.startRecording.matches)
const recordingStartedQueue = defineActionQueue(ECSRecordingActions.recordingStarted.matches)
const stopRecordingQueue = defineActionQueue(ECSRecordingActions.stopRecording.matches)
const playbackChangedQueue = defineActionQueue(ECSRecordingActions.playbackChanged.matches)

const execute = () => {
const recordingState = getMutableState(RecordingState)

for (const action of recordingStartedQueue()) {
recordingState.started.set(true)
recordingState.recordingID.set(action.recordingID)
}

for (const action of startRecordingQueue()) {
recordingState.started.set(true)
}

for (const action of stopRecordingQueue()) {
recordingState.started.set(false)
recordingState.recordingID.set(null)
}

for (const action of playbackChangedQueue()) {
recordingState.playback.set(action.playing ? action.recordingID : null)
}
}

export const RecordingServiceSystem = defineSystem({
uuid: 'ee.client.RecordingServiceSystem',
execute
execute: () => {
receiveActions(RecordingState)
}
})
Loading

0 comments on commit 83660c6

Please sign in to comment.