Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.
Open
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
259 changes: 151 additions & 108 deletions packages/editor/src/components/dialogs/CreatePrefabPanelDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
removeEntity,
setComponent
} from '@etherealengine/ecs'
import { updateModelResource } from '@etherealengine/engine/src/assets/functions/resourceLoaderFunctions'
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'
Expand All @@ -60,130 +61,172 @@ export default function CreatePrefabPanel({ entity }: { entity: Entity }) {
const prefabName = useHookstate<string>('prefab')
const prefabTag = useHookstate<string[]>([])
const { t } = useTranslation()

const isOverwriteModalVisible = useHookstate(false)
const isOverwriteConfirmed = useHookstate(false)
const onExportPrefab = async () => {
const editorState = getState(EditorState)
const fileName = defaultPrefabFolder.value + '/' + prefabName.value + '.gltf'
const srcProject = editorState.projectName!
const fileURL = pathJoin(config.client.fileServer, 'projects', srcProject, fileName)
try {
const parentEntity = getComponent(entity, EntityTreeComponent).parentEntity
const prefabEntity = createEntity()
const obj = new Scene()
addObjectToGroup(prefabEntity, obj)
proxifyParentChildRelationships(obj)
setComponent(prefabEntity, EntityTreeComponent, { parentEntity })
setComponent(prefabEntity, NameComponent, prefabName.value)
const entityTransform = getComponent(entity, TransformComponent)
const position = entityTransform.position.clone()
const rotation = entityTransform.rotation.clone()
const scale = entityTransform.scale.clone()
setComponent(prefabEntity, TransformComponent, {
position,
rotation,
scale
})
setComponent(entity, TransformComponent, {
position: new Vector3(0, 0, 0),
rotation: new Quaternion().identity(),
scale: new Vector3(1, 1, 1)
})
setComponent(entity, EntityTreeComponent, { parentEntity: prefabEntity })
getMutableState(SelectionState).selectedEntities.set([])
await exportRelativeGLTF(prefabEntity, srcProject, fileName)

const resources = await Engine.instance.api.service(staticResourcePath).find({
const resourcesold = await Engine.instance.api.service(staticResourcePath).find({
query: { key: 'projects/' + srcProject + '/' + fileName }
})
if (resources.data.length === 0) {
throw new Error('User not found')
}
const resource = resources.data[0]
const tags = [...prefabTag.value]
await Engine.instance.api.service(staticResourcePath).patch(resource.id, { tags: tags, project: srcProject })
if (resourcesold.data.length !== 0 && !isOverwriteConfirmed.value) {
//throw new Error('Duplicate file')
console.log('this name already exist, click confirm to overwrite the prefab')
await isOverwriteModalVisible.set(true)
} else {
const prefabEntity = createEntity()
const obj = new Scene()
addObjectToGroup(prefabEntity, obj)
proxifyParentChildRelationships(obj)
setComponent(prefabEntity, EntityTreeComponent, { parentEntity })
setComponent(prefabEntity, NameComponent, prefabName.value)
const entityTransform = getComponent(entity, TransformComponent)
const position = entityTransform.position.clone()
const rotation = entityTransform.rotation.clone()
const scale = entityTransform.scale.clone()
setComponent(prefabEntity, TransformComponent, {
position,
rotation,
scale
})
setComponent(entity, TransformComponent, {
position: new Vector3(0, 0, 0),
rotation: new Quaternion().identity(),
scale: new Vector3(1, 1, 1)
})
setComponent(entity, EntityTreeComponent, { parentEntity: prefabEntity })

removeEntity(prefabEntity)
EditorControlFunctions.removeObject([entity])
const sceneID = getComponent(parentEntity, SourceComponent)
const reactor = startReactor(() => {
const documentState = useHookstate(getMutableState(GLTFDocumentState))
const nodes = documentState[sceneID].nodes
useEffect(() => {
if (!entityExists(entity)) {
const { entityUUID } = EditorControlFunctions.createObjectFromSceneElement(
[
{ name: ModelComponent.jsonID, props: { src: fileURL } },
{ name: TransformComponent.jsonID, props: { position, rotation, scale } }
],
parentEntity
)
getMutableState(SelectionState).selectedEntities.set([entityUUID])
reactor.stop()
} else {
console.log('Entity not removed')
}
}, [nodes])
return null
})
PopoverState.hidePopupover()
defaultPrefabFolder.set('assets/custom-prefabs')
prefabName.set('prefab')
prefabTag.set([])
await exportRelativeGLTF(prefabEntity, srcProject, fileName).then(() => {
updateModelResource(fileURL)
})

const resources = await Engine.instance.api.service(staticResourcePath).find({
query: { key: 'projects/' + srcProject + '/' + fileName }
})
if (resources.data.length === 0) {
throw new Error('User not found')
}
const resource = resources.data[0]
const tags = [...prefabTag.value]
await Engine.instance.api.service(staticResourcePath).patch(resource.id, { tags: tags, project: srcProject })

removeEntity(prefabEntity)
await EditorControlFunctions.removeObject([entity])
//await EditorControlFunctions.removeObject([prefabEntity])
const sceneID = getComponent(parentEntity, SourceComponent)
const reactor = startReactor(() => {
const documentState = useHookstate(getMutableState(GLTFDocumentState))
const nodes = documentState[sceneID].nodes
useEffect(() => {
if (!entityExists(entity)) {
const { entityUUID } = EditorControlFunctions.createObjectFromSceneElement(
[
{ name: ModelComponent.jsonID, props: { src: fileURL } },
{ name: TransformComponent.jsonID, props: { position, rotation, scale } }
],
parentEntity
)

updateModelResource(fileURL)
getMutableState(SelectionState).selectedEntities.set([entityUUID])
reactor.stop()
} else {
console.log('Entity not removed')
}
}, [nodes])

return null
})

PopoverState.hidePopupover()
defaultPrefabFolder.set('assets/custom-prefabs')
prefabName.set('prefab')
prefabTag.set([])
isOverwriteModalVisible.set(false)
isOverwriteConfirmed.set(false)
}
} catch (e) {
console.error(e)
}
}
return (
<Modal
title="Create Prefab"
onSubmit={onExportPrefab}
className="w-[50vw] max-w-2xl"
onClose={PopoverState.hidePopupover}
>
<Input
value={defaultPrefabFolder.value}
onChange={(event) => defaultPrefabFolder.set(event.target.value)}
label="Default Save Folder"
/>
<Input value={prefabName.value} onChange={(event) => prefabName.set(event.target.value)} label="Name" />
<>
{!isOverwriteModalVisible.value && !isOverwriteConfirmed.value && (
<Modal
title="Create Prefab"
onSubmit={onExportPrefab}
className="w-[50vw] max-w-2xl"
onClose={PopoverState.hidePopupover}
>
<Input
value={defaultPrefabFolder.value}
onChange={(event) => defaultPrefabFolder.set(event.target.value)}
label="Default Save Folder"
/>
<Input value={prefabName.value} onChange={(event) => prefabName.set(event.target.value)} label="Name" />

<Button
size="small"
variant="outline"
className="text-left text-xs"
onClick={() => {
prefabTag.set([...(prefabTag.value ?? []), ''])
}}
>
{t('editor:layout.filebrowser.fileProperties.addTag')}
</Button>
<div>
{(prefabTag.value ?? []).map((tag, index) => (
<div style={{ display: 'flex', flexDirection: 'row', margin: '0, 16px 0 0' }}>
<Input
key={index}
label={t('editor:layout.filebrowser.fileProperties.tag')}
onChange={(event) => {
const tags = [...prefabTag.value]
tags[index] = event.target.value
prefabTag.set(tags)
}}
value={prefabTag.value[index]}
/>
<Button
onClick={() => {
prefabTag.set(prefabTag.value.filter((_, i) => i !== index))
}}
size="small"
variant="outline"
className="text-left text-xs"
>
{' '}
x{' '}
</Button>
<Button
size="small"
variant="outline"
className="text-left text-xs"
onClick={() => {
prefabTag.set([...(prefabTag.value ?? []), ''])
}}
>
{t('editor:layout.filebrowser.fileProperties.addTag')}
</Button>
<div>
{(prefabTag.value ?? []).map((tag, index) => (
<div style={{ display: 'flex', flexDirection: 'row', margin: '0, 16px 0 0' }}>
<Input
key={index}
label={t('editor:layout.filebrowser.fileProperties.tag')}
onChange={(event) => {
const tags = [...prefabTag.value]
tags[index] = event.target.value
prefabTag.set(tags)
}}
value={prefabTag.value[index]}
/>
<Button
onClick={() => {
prefabTag.set(prefabTag.value.filter((_, i) => i !== index))
}}
size="small"
variant="outline"
className="text-left text-xs"
>
{' '}
x{' '}
</Button>
</div>
))}
</div>
</Modal>
)}
{/* Overwrite Confirmation Modal */}
{isOverwriteModalVisible.value && (
<Modal
title="Overwrite Prefab"
onSubmit={() => {
isOverwriteConfirmed.set(true)
isOverwriteModalVisible.set(false)
onExportPrefab()
}}
onClose={() => {
isOverwriteConfirmed.set(false)
isOverwriteModalVisible.set(false)
}}
>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<p>Prefab with this name already exists. You will overwrite it.</p>
</div>
))}
</div>
</Modal>
</Modal>
)}
</>
)
}