Skip to content

Commit

Permalink
feat: add assets folder structure
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoecheza committed Jun 6, 2023
1 parent e7e759e commit c03aa0b
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 51 deletions.
12 changes: 9 additions & 3 deletions packages/@dcl/inspector/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@

# Inspector

## Developing
Run `npm start` to spawn esbuild in `watch` mode. This serves the `public/` folder, every change triggers rebuilding the `bundle.js` and you'll need refresh the page. The server created is in `localhost:8000` by default, an initial message is printed but it probably quickly missed.
## Development
Run `npm start` to spawn esbuild in `watch` mode. This serves the `public/` folder, every change triggers rebuilding the `bundle.js` and you'll need refresh the page. The server created is in `localhost:8000` by default, an initial message is printed but it probably quickly missed.

This also rebuilds the library section (data-layer) and exposes in `dist/` folder.

### Running with data-layer
For faster development experience, we are faking the file system for the data-layer, if you want to use your actual file-system, you can either:

* Run the extension from VSCode on a scene
* Run `sdk-commands start -- --data-layer --port 8001` in a scene & go to http://localhost:8000/?ws=ws://127.0.0.1:8001/data-layer

## Build
The `make build ` in the repo root builds all the necessary for package publishment.
The `make build ` in the repo root builds all the necessary for package publishment.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function HierarchyIcon({ value, hasChildrens, isOpen }: { value: Entity; hasChil
const EntityTree = Tree<Entity>()

const Hierarchy: React.FC = () => {
const { addChild, setParent, remove, rename, toggle, getId, getChildren, getLabel, isOpen, canRename, canRemove } =
const { addChild, setParent, remove, rename, toggle, getId, getChildren, getLabel, isOpen, isHidden, canRename, canRemove } =
useTree()
const selectedEntity = useSelectedEntity()

Expand Down Expand Up @@ -62,6 +62,7 @@ const Hierarchy: React.FC = () => {
)}
isOpen={isOpen}
isSelected={isSelected}
isHidden={isHidden}
canRename={canRename}
canRemove={canRemove}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const ImportAsset = withSdk<PropTypes>(({ sdk, onSave }) => {
setAssetPackageName(file.name.trim().replaceAll(' ', '_').toLowerCase().split('.')[0])
}

const destFolder = 'assets/'
const handleSave = () => {
const reader = new FileReader()
if (!file) return
Expand All @@ -95,9 +94,11 @@ const ImportAsset = withSdk<PropTypes>(({ sdk, onSave }) => {
const content: Map<string, Uint8Array> = new Map()
content.set(file.name, new Uint8Array(binary))

const basePath = (await sdk!.dataLayer.getProjectData({})).path

await sdk!.dataLayer.importAsset({
content,
basePath: destFolder,
basePath,
assetPackageName
})
onSave()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ function ProjectView({ folders }: Props) {
getLabel={(val: string) => <span>{tree.get(val)?.name ?? val}</span>}
isOpen={isOpen}
isSelected={(val: string) => lastSelected === val}
isHidden={(val: string) => val === ROOT}
canRename={() => false}
canRemove={(val) => tree.get(val)?.type === 'asset'}
canToggle={() => true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const Renderer: React.FC = () => {
const importBuilderAsset = async (asset: IAsset) => {
const position = await getDropPosition()
const fileContent: Record<string, Uint8Array> = {}
const destFolder = 'world-assets'
const destFolder = 'builder'
const assetPackageName = asset.name.trim().replaceAll(' ', '_').toLowerCase()
const path = Object.keys(asset.contents).find(($) => isAsset($))
setIsLoading(true)
Expand Down
4 changes: 4 additions & 0 deletions packages/@dcl/inspector/src/components/Tree/Tree.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
background-color: var(--vscode-accent-blue);
}

.Tree .item.hidden {
display: none;
}

.Tree > div:first-child > div:not(.contexify) {
width: 100%;
display: flex;
Expand Down
13 changes: 10 additions & 3 deletions packages/@dcl/inspector/src/components/Tree/Tree.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useState } from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { IoIosArrowDown, IoIosArrowForward } from 'react-icons/io'
import cx from 'classnames'

import { withContextMenu } from '../../hoc/withContextMenu'
import { Input } from '../Input'
Expand All @@ -19,6 +20,7 @@ type Props<T> = {
getLabel: (value: T) => string | JSX.Element
isOpen: (value: T) => boolean
isSelected: (value: T) => boolean
isHidden: (value: T) => boolean
canRename?: (value: T) => boolean
canAddChild?: (value: T) => boolean
canRemove?: (value: T) => boolean
Expand Down Expand Up @@ -51,6 +53,7 @@ export function Tree<T>() {
getLabel,
isOpen,
isSelected,
isHidden,
onSetParent,
canRename,
canAddChild,
Expand All @@ -67,6 +70,7 @@ export function Tree<T>() {
const label = getLabel(value)
const open = isOpen(value)
const selected = isSelected(value)
const hidden = isHidden(value)
const enableRename = canRename ? canRename(value) : true
const enableAddChild = canAddChild ? canAddChild(value) : true
const enableRemove = canRemove ? canRemove(value) : true
Expand Down Expand Up @@ -141,9 +145,11 @@ export function Tree<T>() {
extra: extraContextMenu
}

const nodeClassnames = cx({ selected, item: true, hidden })

return (
<div ref={ref} className={`Tree ${className || ''}`}>
<div style={getLevelStyles(level)} onClick={handleToggleExpand} className={selected ? 'selected item' : 'item'}>
<div style={getLevelStyles(level)} onClick={handleToggleExpand} className={nodeClassnames}>
<ContextMenu {...controlsProps} />
<div style={getEditModeStyles(editMode)}>
{props.getIcon ? props.getIcon(value) : open ? <IoIosArrowDown /> : <IoIosArrowForward />}
Expand All @@ -162,16 +168,17 @@ export function Tree<T>() {

function TreeChildren<T>(props: Props<T>) {
const CompTree = Tree<T>()
const { value, level = getDefaultLevel(), getChildren, getId, isOpen } = props
const { value, level = getDefaultLevel(), getChildren, getId, isOpen, isHidden } = props
const children = getChildren(value)
const open = isOpen(value)
const hidden = isHidden(value)

if (!children.length || !open) return null

return (
<div style={getExpandStyles(open)}>
{children.map(($) => (
<CompTree {...props} value={$} level={level + 1} key={getId($)} />
<CompTree {...props} value={$} level={hidden ? level : level + 1} key={getId($)} />
))}
</div>
)
Expand Down
8 changes: 8 additions & 0 deletions packages/@dcl/inspector/src/hooks/sdk/useTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ export const useTree = () => {
[sdk]
)

const isHidden = useCallback(
(entity: Entity) => {
return false
},
[sdk]
)

const addChild = useCallback(
async (parent: Entity, label: string) => {
if (!sdk) return
Expand Down Expand Up @@ -134,6 +141,7 @@ export const useTree = () => {
getChildren,
getLabel,
isOpen,
isHidden,
canRename,
canRemove
}
Expand Down
27 changes: 24 additions & 3 deletions packages/@dcl/inspector/src/lib/data-layer/host/fs-utils.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
import { FileSystemInterface } from '../types'

export async function getFilesInDirectory(
fileSystem: FileSystemInterface,
fs: FileSystemInterface,
dirPath: string,
files: string[],
recursive: boolean = true,
ignore: string[] = [] // This functionality can be extended, now only 'absolute' path can be ignored
) {
const currentDirFiles = await fileSystem.readdir(dirPath)
const currentDirFiles = await fs.readdir(dirPath)
for (const currentPath of currentDirFiles) {
if (ignore.includes(currentPath.name)) continue

const slashIfRequire = (dirPath.length && !dirPath.endsWith('/') && '/') || ''
const fullPath = dirPath + slashIfRequire + currentPath.name

if (currentPath.isDirectory && recursive) {
await getFilesInDirectory(fileSystem, fullPath, files, recursive)
await getFilesInDirectory(fs, fullPath, files, recursive)
} else {
files.push(fullPath)
}
}
return files
}

export const DIRECTORY = {
ASSETS: 'assets'
}

export function createAssetsFs(fs: FileSystemInterface): FileSystemInterface {
const ASSETS_PATH = DIRECTORY.ASSETS

function withAssetDir(filePath: string = '') {
return `${ASSETS_PATH}/${filePath}`
}

return {
existFile: (filePath: string) => fs.existFile(withAssetDir(filePath)),
readFile: (filePath: string) => fs.readFile(withAssetDir(filePath)),
writeFile: (filePath: string, content: Buffer) => fs.writeFile(withAssetDir(filePath), content),
readdir: (filePath: string) => fs.readdir(withAssetDir(filePath)),
rm: (filePath: string) => fs.rm(withAssetDir(filePath)),
cwd: async () => `${(await fs.cwd())}/${ASSETS_PATH}`
}
}
40 changes: 23 additions & 17 deletions packages/@dcl/inspector/src/lib/data-layer/host/rpc-methods.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Entity, EntityMappingMode, IEngine, Composite, OnChangeFunction, CompositeDefinition } from '@dcl/ecs'

import { DataLayerRpcServer, FileSystemInterface } from '../types'
import { getFilesInDirectory } from './fs-utils'
import { createAssetsFs, getFilesInDirectory } from './fs-utils'
import { dumpEngineToComposite, dumpEngineToCrdtCommands } from './utils/engine-to-composite'
import { CompositeManager, createFsCompositeProvider } from './utils/fs-composite-provider'
import { stream } from './stream'
Expand Down Expand Up @@ -43,17 +43,17 @@ export async function initRpcMethods(
engine: IEngine,
onChanges: OnChangeFunction[]
): Promise<DataLayerRpcServer> {
const assetsFs = createAssetsFs(fs)
let inspectorPreferences = await readPreferencesFromFile(fs, INSPECTOR_PREFERENCES_PATH)

// Look for a composite
const currentCompositeResourcePath = 'main.composite'

if (!(await fs.existFile(currentCompositeResourcePath))) {
await fs.writeFile(currentCompositeResourcePath, Buffer.from(JSON.stringify(minimalComposite), 'utf-8'))
if (!(await assetsFs.existFile(currentCompositeResourcePath))) {
await assetsFs.writeFile(currentCompositeResourcePath, Buffer.from(JSON.stringify(minimalComposite), 'utf-8'))
}

const compositeProvider = await createFsCompositeProvider(fs)
const dumpEngineAndGetComposite = setupEngineDump(fs, engine, compositeProvider, currentCompositeResourcePath)
const compositeProvider = await createFsCompositeProvider(assetsFs)
const dumpEngineAndGetComposite = setupEngineDump(assetsFs, engine, compositeProvider, currentCompositeResourcePath)
const mainComposite = compositeProvider.getCompositeOrNull(currentCompositeResourcePath)
if (mainComposite) {
Composite.instance(engine, mainComposite, compositeProvider, {
Expand All @@ -68,12 +68,12 @@ export async function initRpcMethods(

let dirty = false
let composite: CompositeDefinition
const undoRedo = initUndoRedo(fs, engine, () => composite)
const scene = initSceneProvider(fs)
const undoRedo = initUndoRedo(assetsFs, engine, () => composite)
const sceneProvider = await initSceneProvider(fs)

// Create containers and attach onChange logic.
onChanges.push(undoRedo.onChange)
onChanges.push(scene.onChange)
onChanges.push(sceneProvider.onChange)

// TODO: review this
// Dump composite to the FS on every tick
Expand Down Expand Up @@ -108,9 +108,9 @@ export async function initRpcMethods(
return stream(iter, { engine }, () => undoRedo?.addUndoCrdt())
},
async getAssetData(req) {
if (await fs.existFile(req.path)) {
if (await assetsFs.existFile(req.path)) {
return {
data: await fs.readFile(req.path)
data: await assetsFs.readFile(req.path)
}
}

Expand All @@ -120,7 +120,7 @@ export async function initRpcMethods(
const extensions = ['.glb', '.png', '.composite', '.composite.bin', '.gltf', '.jpg']
const ignore = ['.git', 'node_modules']

const files = (await getFilesInDirectory(fs, '', [], true, ignore)).filter((item) => {
const files = (await getFilesInDirectory(assetsFs, '', [], true, ignore)).filter((item) => {
const itemLower = item.toLowerCase()
return extensions.some((ext) => itemLower.endsWith(ext))
})
Expand All @@ -136,19 +136,19 @@ export async function initRpcMethods(
const undoAcc: FileOperation[] = []
for (const [fileName, fileContent] of req.content) {
const filePath = (baseFolder + fileName).replaceAll('//', '/')
const prevValue = (await fs.existFile(filePath)) ? await fs.readFile(filePath) : null
const prevValue = (await assetsFs.existFile(filePath)) ? await assetsFs.readFile(filePath) : null
undoAcc.push({ prevValue, newValue: fileContent, path: filePath })
await upsertAsset(fs, filePath, fileContent)
await upsertAsset(assetsFs, filePath, fileContent)
}
undoRedo.addUndoFile(undoAcc)
return {}
},
async removeAsset(req) {
const filePath = req.path
// TODO: remove ALL gltf/glb related files...
if (await fs.existFile(filePath)) {
const prevValue = await fs.readFile(filePath)
await fs.rm(filePath)
if (await assetsFs.existFile(filePath)) {
const prevValue = await assetsFs.readFile(filePath)
await assetsFs.rm(filePath)
undoRedo.addUndoFile([{ prevValue, newValue: null, path: filePath }])
}
return {}
Expand All @@ -164,6 +164,12 @@ export async function initRpcMethods(
inspectorPreferences = req
await fs.writeFile(INSPECTOR_PREFERENCES_PATH, serializeInspectorPreferences(req))
return {}
},
async getProjectData() {
const scene = sceneProvider.getScene()
return {
path: scene.display?.title || (await fs.cwd())
}
}
}
}
Loading

0 comments on commit c03aa0b

Please sign in to comment.