Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,7 @@

.resizeable-screen-fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
inset: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
Expand Down
12 changes: 7 additions & 5 deletions packages/editor/src/components/hierarchy/HierarchyTreeNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
useComponent,
useOptionalComponent
} from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { entityExists } from '@etherealengine/engine/src/ecs/functions/EntityFunctions'
import {
EntityTreeComponent,
getEntityNodeArrayFromEntities
Expand Down Expand Up @@ -266,11 +267,12 @@ export const HierarchyTreeNode = (props: HierarchyTreeNodeProps) => {
}, [preview])

const collectNodeMenuProps = useCallback(() => node, [node])
const editors = node.entityNode
? getAllComponents(node.entityNode as Entity)
.map((c) => EntityNodeEditor.get(c)!)
.filter((c) => !!c)
: []
const editors =
typeof node.entityNode === 'number' && entityExists(node.entityNode as Entity)
? getAllComponents(node.entityNode as Entity)
.map((c) => EntityNodeEditor.get(c)!)
.filter((c) => !!c)
: []
const IconComponent = editors.length && editors[editors.length - 1].iconComponent
const renaming = data.renamingNode && data.renamingNode.entity === node.entityNode
const marginLeft = node.depth > 0 ? node.depth * 8 + 20 : 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const Object3DNodeEditor = (props: Object3DProps) => {
}}
onRelease={() => {
dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}}
/>
</InputGroup>
Expand All @@ -216,7 +216,7 @@ export const Object3DNodeEditor = (props: Object3DProps) => {
}}
onRelease={() => {
dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}}
/>
</InputGroup>
Expand All @@ -232,7 +232,7 @@ export const Object3DNodeEditor = (props: Object3DProps) => {
}}
onRelease={() => {
dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}}
/>
</InputGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const TransformPropertyGroup: EditorComponentType = (props) => {

const onRelease = () => {
dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}

const onChangeDynamicLoad = (value) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/editor/src/components/properties/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const updateProperties = <C extends Component>(

EditorControlFunctions.modifyProperty(affectedNodes, component, properties)

dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}

export function traverseScene<T>(
Expand Down
17 changes: 10 additions & 7 deletions packages/editor/src/functions/EditorControlFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const addOrRemoveComponent = <C extends Component<any, any>>(
dispatchAction(EngineActions.sceneObjectUpdate({ entities: nodes as Entity[] }))
dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(SelectionAction.changedSceneGraph({}))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}

/**
Expand Down Expand Up @@ -120,7 +120,7 @@ const modifyProperty = <C extends Component<any, any>>(
)
dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(SelectionAction.changedSceneGraph({}))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}

const modifyObject3d = (nodes: string[], properties: { [_: string]: any }[]) => {
Expand Down Expand Up @@ -213,7 +213,7 @@ const createObjectFromPrefab = (

dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(SelectionAction.changedSceneGraph({}))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))

return newEntity
}
Expand Down Expand Up @@ -287,7 +287,7 @@ const duplicateObject = (nodes: EntityOrObjectUUID[]) => {

dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(SelectionAction.changedSceneGraph({}))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}

const tempMatrix = new Matrix4()
Expand Down Expand Up @@ -518,7 +518,7 @@ const reparentObject = (

dispatchAction(EditorAction.sceneModified({ modified: true }))
dispatchAction(SelectionAction.changedSceneGraph({}))
dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(EditorHistoryAction.createSnapshot({}))
}

/** @todo - grouping currently doesnt take into account parentEntity or beforeEntity */
Expand Down Expand Up @@ -546,7 +546,9 @@ const groupObjects = (
*/
const removeObject = (nodes: EntityOrObjectUUID[]) => {
cancelGrabOrPlacement()
replaceSelection([])

/** we have to manually set this here or it will cause react errors when entities are removed */
getMutableState(SelectionState).selectedEntities.set([])

const removedParentNodes = getEntityNodeArrayFromEntities(filterParentEntities(nodes, undefined, true, false))
const scene = Engine.instance.scene
Expand All @@ -562,7 +564,8 @@ const removeObject = (nodes: EntityOrObjectUUID[]) => {
}
}

dispatchAction(EditorHistoryAction.createSnapshot({ modify: true }))
dispatchAction(SelectionAction.updateSelection({ selectedEntities: [] }))
dispatchAction(EditorHistoryAction.createSnapshot({ selectedEntities: [] }))
}
/**
*
Expand Down
62 changes: 39 additions & 23 deletions packages/editor/src/services/EditorHistory.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { diff } from 'deep-object-diff'

import { EntityUUID } from '@etherealengine/common/src/interfaces/EntityUUID'
import { SceneData, SceneJson } from '@etherealengine/common/src/interfaces/SceneInterface'
import { matches, Validator } from '@etherealengine/engine/src/common/functions/MatchesUtils'
import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity'
import { SceneState } from '@etherealengine/engine/src/ecs/classes/Scene'
import { getComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { defineSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions'
import { UUIDComponent } from '@etherealengine/engine/src/scene/components/UUIDComponent'
import { serializeWorld } from '@etherealengine/engine/src/scene/functions/serializeWorld'
import { defineAction, defineState, getMutableState, getState, NO_PROXY } from '@etherealengine/hyperflux'
import {
removeSceneEntitiesFromOldJSON,
updateSceneEntitiesFromJSON
} from '@etherealengine/engine/src/scene/systems/SceneLoadingSystem'
import { defineAction, defineState, getMutableState, getState } from '@etherealengine/hyperflux'
import { defineActionQueue, dispatchAction, Topic } from '@etherealengine/hyperflux/functions/ActionFunctions'

import { SelectionAction, SelectionState } from './SelectionServices'

export const EditorTopic = 'editor' as Topic

export type EditorStateSnapshot = {
selectedEntities?: Array<Entity | string>
data?: SceneData
selectedEntities: Array<EntityUUID | string>
data: SceneData
}

export const EditorHistoryState = defineState({
Expand Down Expand Up @@ -53,19 +62,24 @@ export class EditorHistoryAction {

static createSnapshot = defineAction({
type: 'ee.editor.EditorHistory.CREATE_SNAPSHOT' as const,
/** only one of selectedEntities OR modify - @todo should we make these separate actions? */
selectedEntities: matches.array.optional() as Validator<unknown, Array<Entity | string> | undefined>,
modify: matches.boolean.optional()
selectedEntities: matches.array.optional() as Validator<unknown, Array<Entity | string> | undefined>
})
}

const applyCurrentSnapshot = () => {
const state = getMutableState(EditorHistoryState)
const snapshot = state.history[state.index.value].get(NO_PROXY)
console.log('Applying snapshot', state.index.value, snapshot)
if (snapshot.data) getMutableState(SceneState).sceneData.set(snapshot.data)
const state = getState(EditorHistoryState)
const snapshot = state.history[state.index]
if (snapshot.data) {
getMutableState(SceneState).sceneData.ornull!.scene.set(snapshot.data.scene)
removeSceneEntitiesFromOldJSON()
updateSceneEntitiesFromJSON(snapshot.data.scene.root)
}
if (snapshot.selectedEntities)
dispatchAction(SelectionAction.updateSelection({ selectedEntities: snapshot.selectedEntities }))
dispatchAction(
SelectionAction.updateSelection({
selectedEntities: snapshot.selectedEntities.map((uuid) => UUIDComponent.entitiesByUUID[uuid] ?? uuid)
})
)
}

const undoQueue = defineActionQueue(EditorHistoryAction.undo.matches)
Expand All @@ -75,6 +89,8 @@ const appendSnapshotQueue = defineActionQueue(EditorHistoryAction.appendSnapshot
const modifyQueue = defineActionQueue(EditorHistoryAction.createSnapshot.matches)

const execute = () => {
const selectedEntitiesState = getState(SelectionState)

const state = getMutableState(EditorHistoryState)
for (const action of undoQueue()) {
if (state.index.value <= 0) continue
Expand All @@ -89,9 +105,13 @@ const execute = () => {
}

for (const action of clearHistoryQueue()) {
const selectedEntities = selectedEntitiesState.selectedEntities.map((entity) =>
typeof entity === 'number' ? getComponent(entity, UUIDComponent) : entity
) as Array<EntityUUID | string>
const data = { scene: serializeWorld(getState(SceneState).sceneEntity) } as any as SceneData
state.merge({
index: 0,
history: [{ data: { scene: serializeWorld(getState(SceneState).sceneEntity) } as any as SceneData }]
history: [{ data, selectedEntities }]
})
}

Expand All @@ -111,19 +131,15 @@ const execute = () => {
}
}

const selectedEntitiesState = getState(SelectionState)

/** Local only - serialize world then push to CRDT */
for (const action of modifyQueue()) {
if (action.modify) {
const data = { scene: serializeWorld(getState(SceneState).sceneEntity) } as any as SceneData
state.history.set([...state.history.get(NO_PROXY).slice(0, state.index.value + 1), { data }])
state.index.set(state.index.value + 1)
} else if (action.selectedEntities) {
const selectedEntities = action.selectedEntities ?? selectedEntitiesState.selectedEntities
state.history.set([...state.history.get(NO_PROXY).slice(0, state.index.value + 1), { selectedEntities }])
state.index.set(state.index.value + 1)
}
const editorHistory = getState(EditorHistoryState)
const data = { scene: serializeWorld(getState(SceneState).sceneEntity) } as any as SceneData
const selectedEntities = (action.selectedEntities ?? selectedEntitiesState.selectedEntities).map((entity) =>
typeof entity === 'number' ? getComponent(entity, UUIDComponent) : entity
) as Array<EntityUUID | string>
state.history.set([...editorHistory.history.slice(0, state.index.value + 1), { data, selectedEntities }])
state.index.set(state.index.value + 1)
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/editor/src/services/SelectionServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
removeComponent,
setComponent
} from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { entityExists } from '@etherealengine/engine/src/ecs/functions/EntityFunctions'
import { EntityOrObjectUUID } from '@etherealengine/engine/src/ecs/functions/EntityTree'
import { defineSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions'
import { SelectTagComponent } from '@etherealengine/engine/src/scene/components/SelectTagComponent'
Expand Down Expand Up @@ -79,7 +80,7 @@ const execute = () => {
cancelGrabOrPlacement()
/** update SelectTagComponent to only newly selected entities */
for (const entity of action.selectedEntities.concat(...selectionState.selectedEntities.value)) {
if (typeof entity === 'number') {
if (typeof entity === 'number' && entityExists(entity)) {
const add = action.selectedEntities.includes(entity)
if (add && !hasComponent(entity, SelectTagComponent)) setComponent(entity, SelectTagComponent)
if (!add && hasComponent(entity, SelectTagComponent)) removeComponent(entity, SelectTagComponent)
Expand Down
15 changes: 12 additions & 3 deletions packages/engine/src/ecs/classes/Scene.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { Color, Texture } from 'three'

import { EntityUUID } from '@etherealengine/common/src/interfaces/EntityUUID'
import { SceneData } from '@etherealengine/common/src/interfaces/SceneInterface'
import { defineState } from '@etherealengine/hyperflux'
import { defineState, getState } from '@etherealengine/hyperflux'

import { UUIDComponent } from '../../scene/components/UUIDComponent'
import { UndefinedEntity } from './Entity'

/** @todo support multiple scenes */

export const SceneState = defineState({
name: 'SceneState',
initial: () => ({
sceneData: null as SceneData | null,
sceneEntity: UndefinedEntity,
/** @todo support multiple scenes */
// sceneEntities: {} as Record<string /* SceneID */, EntityUUID>,
background: null as null | Color | Texture
})
})

// export const

// export const getActiveSceneEntity = () => {
// const state = getState(SceneState)
// return UUIDComponent.entitiesByUUID[state.sceneEntities[state.sceneEntity]]
// }
Loading