diff --git a/inspector/data.js b/inspector/data.js index 43ab339..685dfc5 100644 --- a/inspector/data.js +++ b/inspector/data.js @@ -1,6 +1,6 @@ import { signal, effect } from "@preact/signals" import { parse } from "./mudparse.js" -import { parseHabitatObject } from "./neohabitat.js" +import { parseHabitatRegion } from "./neohabitat.js" import { decodeCharset } from "./codec.js" import { getFile } from "./shim.js" @@ -104,23 +104,7 @@ export const useJson = (url, defaultValue) => { } export const useHabitatJson = (url) => { - return fetchAndCache(url, async (response) => { - const value = parseHabitatObject(await response.text()) - if (!Array.isArray(value) || value.length == 0) { - throw new Error(`Not a valid Habitat JSON file: ${url}`) - } - return value.map(obj => { - if (obj && obj.mods && obj.mods.length > 0) { - const mod = obj.mods[0] - mod.x = mod.x ?? 0 - mod.y = mod.y ?? 0 - mod.orientation = mod.orientation ?? 0 - mod.style = mod.style ?? 0 - mod.gr_state = mod.gr_state ?? 0 - } - return obj - }) - }, []) + return fetchAndCache(url, async (response) => parseHabitatRegion(await response.text()), []) } export const betaMud = lazySignal(null, async () => diff --git a/inspector/edit.html b/inspector/edit.html index dd45d5b..8724dd6 100644 --- a/inspector/edit.html +++ b/inspector/edit.html @@ -23,7 +23,8 @@ import { useHabitatJson, errorBucket, until } from "./data.js" import { regionView } from "./region.js" import { navigationView } from "./navigate.js" - import { selectionInteraction, propEditor, objectChooser, createEditTracker } from "./edit.js" + import { parseHabitatRegion } from "./neohabitat.js" + import { selectionInteraction, propEditor, objectPanel, createEditTracker } from "./edit.js" import { jsonDump, jsonDownload } from "./show.js" const q = (k) => (new URLSearchParams(window.location.search)).get(k) @@ -47,11 +48,23 @@

Region Editor - <${regionName} objects=${objectList.value}/>

<${propEditor} objects=${objectList.value}/>
-
- tracker.undo()}>Undo | - tracker.redo()}>Redo +
+
- <${objectChooser} objects=${objectList.value}/> + <${objectPanel} objectList=${objectList} tracker=${tracker}/>
<${jsonDump} heading=${html`Region JSON (<${jsonDownload} value=${objectList.value}>Download)`} diff --git a/inspector/edit.js b/inspector/edit.js index 04a98ed..dd8f4cd 100644 --- a/inspector/edit.js +++ b/inspector/edit.js @@ -26,17 +26,21 @@ export const createEditTracker = () => { const editHistory = [] const redoHistory = [] - const update = (obj, key, value) => { + const update = (obj, key, value, splicing = null) => { const result = Array.isArray(obj) ? [...obj] : {...obj} - result[key] = value + if (splicing === null) { + result[key] = value + } else { + result.splice(key, splicing, ...value) + } return result } - const updateIn = (obj, place, key, value) => { + const updateIn = (obj, place, key, value, splicing) => { if (place.length == 0) { - return update(obj, key, value) + return update(obj, key, value, splicing) } else { - return update(obj, place[0], updateIn(obj[place[0]], place.slice(1), key, value)) + return update(obj, place[0], updateIn(obj[place[0]], place.slice(1), key, value, splicing)) } } @@ -48,25 +52,28 @@ export const createEditTracker = () => { return value } - const performEdit = (sig, place, key, value, history) => { - const previous = valueAt(sig, place)[key] - sig.value = updateIn(sig.value, place, key, value) - history.push({ sig, place, key, value, previous }) + const performEdit = (sig, place, key, value, splicing, history) => { + const obj = valueAt(sig, place) + const previous = splicing === null ? obj[key] : obj.slice(key, key + splicing) + sig.value = updateIn(sig.value, place, key, value, splicing) + history.push({ sig, place, key, value, splicing, previous }) } - const change = (sig, place, key, value) => { - performEdit(sig, place, key, value, editHistory) + const change = (sig, place, key, value, splicing = null) => { + performEdit(sig, place, key, value, splicing, editHistory) redoHistory.length = 0 } const undo = (fromHistory = editHistory, toHistory = redoHistory) => { const edit = fromHistory.pop() if (edit) { - performEdit(edit.sig, edit.place, edit.key, edit.previous, toHistory) + const splicing = edit.splicing === null ? null : edit.value.length + performEdit(edit.sig, edit.place, edit.key, edit.previous, splicing, toHistory) } } const redo = () => undo(redoHistory, editHistory) + const dynamicProxy = (targetGetter, handler) => { return new Proxy(targetGetter(), { ownKeys(target) { return Reflect.ownKeys(targetGetter(target)) }, @@ -99,6 +106,7 @@ export const createEditTracker = () => { return { undo, redo, + change, editHistory, redoHistory, trackSignal(sig) { @@ -259,12 +267,28 @@ export const propEditor = ({ objects }) => { } } -export const objectChooser = ({ objects }) => { +const swapItemsAtIndex = (sig, tracker, index) => { + const newValue = [sig.value[index + 1], sig.value[index]] + tracker.change(sig, [], index, newValue, 2) +} + +export const objectPanel = ({ objectList, tracker }) => { const selectionRef = useContext(Selection) + const iselection = objectList.value.findIndex(o => o.ref === selectionRef.value) + const deleteDisabled = iselection <= 0 + const moveUpDisabled = iselection <= 1 + const moveDownDisabled = iselection <= 0 || iselection >= objectList.value.length - 1 + const buttonStyle = "border-radius: 8px; font-size: 16px;" + const disabledStyle = `background-color: #777; color: #ccc; ${buttonStyle}` + const dangerousStyle = `background-color: red; color: white; ${buttonStyle}` + return html` +
+ tracker.undo()}>Undo | tracker.redo()}>Redo +
Objects - ${objects.map(o => html` + ${objectList.value.map(o => html`
`)} + + +
` } diff --git a/inspector/neohabitat.js b/inspector/neohabitat.js index 23a3f08..b0e2a78 100644 --- a/inspector/neohabitat.js +++ b/inspector/neohabitat.js @@ -74,6 +74,24 @@ export function parseHabitatObject(data) { return JSON.parse(templateHabitatObject(data)) } +export function parseHabitatRegion(data) { + const region = parseHabitatObject(data) + if (!Array.isArray(region) || region.length == 0) { + throw new Error(`Not valid Habitat region JSON`) + } + return region.map(obj => { + if (obj && obj.mods && obj.mods.length > 0) { + const mod = obj.mods[0] + mod.x = mod.x ?? 0 + mod.y = mod.y ?? 0 + mod.orientation = mod.orientation ?? 0 + mod.style = mod.style ?? 0 + mod.gr_state = mod.gr_state ?? 0 + } + return obj + }) +} + export function colorsFromOrientation(orientation) { const colorVal = (orientation & 0x78) >> 3 if (orientation & 0x80) {