Skip to content

Commit c201c2b

Browse files
SnaveSutitgitbutler-client
authored andcommitted
🩹 Improve Block & Item Display panel reliability
1 parent 898a004 commit c201c2b

5 files changed

Lines changed: 170 additions & 175 deletions

File tree

src/outliner/vanillaBlockDisplay.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,18 +203,27 @@ export const PREVIEW_CONTROLLER: NodePreviewController = new NodePreviewControll
203203
{
204204
setup(el: VanillaBlockDisplay) {
205205
ResizableOutlinerElement.prototype.preview_controller.setup(el)
206+
207+
// Placeholder wireframe mesh
208+
const geometry = new THREE.BoxGeometry(16, 16, 16)
209+
const cubeMesh = new THREE.Mesh(geometry, Canvas.wireframeMaterial)
210+
cubeMesh.name = el.uuid
211+
cubeMesh.visible = el.visibility
212+
cubeMesh.position.set(8, 8, 8)
213+
el.mesh.add(cubeMesh)
214+
206215
// Setup temp sprite mesh
207-
const material = new THREE.SpriteMaterial({
216+
const spriteMaterial = new THREE.SpriteMaterial({
208217
map: TEMP_MESH_MAP,
209218
alphaTest: 0.1,
210219
sizeAttenuation: false,
211220
})
212-
const sprite = new THREE.Sprite(material)
213-
sprite.scale.setScalar(1 / 32)
214-
const mesh = el.mesh as THREE.Mesh
215-
mesh.add(sprite)
221+
const sprite = new THREE.Sprite(spriteMaterial)
222+
sprite.scale.setScalar(1 / 16)
223+
sprite.position.set(8, 8, 8)
224+
el.mesh.add(sprite)
216225
// @ts-expect-error - Broken BB types
217-
mesh.sprite = sprite
226+
el.mesh.sprite = sprite
218227
},
219228
updateGeometry(el: VanillaBlockDisplay) {
220229
if (!el.mesh) return

src/panels/vanillaBlockDisplayElement/vanillaBlockDisplayElement.svelte

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,80 @@
11
<script lang="ts" module>
2+
import { onDestroy } from 'svelte'
23
import { VanillaBlockDisplay } from '../../outliner/vanillaBlockDisplay'
4+
import EVENTS from '../../util/events'
35
import { localize as translate } from '../../util/lang'
46
import { validateBlock } from '../../util/minecraftUtil'
57
</script>
68

79
<script lang="ts">
8-
interface Props {
9-
selected: VanillaBlockDisplay
10-
}
10+
let selected = $state(VanillaBlockDisplay.selected.at(0))
11+
let block = $derived(selected?.block)
12+
let error = $derived(selected?.error)
1113
12-
let { selected }: Props = $props()
14+
const onSelectionChanged = () => {
15+
selected = VanillaBlockDisplay.selected.at(0)
16+
block = selected?.block
17+
error = selected?.error
18+
}
1319
14-
let block = $derived(selected.block)
15-
let error = $derived(selected.error)
20+
const unsubs = [
21+
EVENTS.UNDO.subscribe(onSelectionChanged),
22+
EVENTS.REDO.subscribe(onSelectionChanged),
23+
EVENTS.UPDATE_SELECTION.subscribe(onSelectionChanged),
24+
]
1625
1726
$effect(() => {
18-
$error = ''
19-
if (selected.block !== block) {
20-
void validateBlock(block)
27+
const thisSelected = selected
28+
const thisBlock = block
29+
error?.set('')
30+
if (thisSelected && thisBlock && thisSelected.block !== thisBlock) {
31+
void validateBlock(thisBlock)
2132
.then(err => {
2233
if (err) {
23-
$error = err
34+
error?.set(err)
2435
console.log('Block validation error:', err)
2536
return
2637
}
27-
console.log('Changing block to', block)
28-
Undo.initEdit({ elements: [selected] })
38+
console.log('Changing block to', thisBlock)
39+
Undo.initEdit({ elements: [thisSelected] })
2940
30-
selected.block = block
41+
thisSelected.block = thisBlock
3142
Project!.saved = false
3243
33-
Undo.finishEdit(`Change Block Display Block to "${block}"`, {
34-
elements: [selected],
44+
Undo.finishEdit(`Change Block Display Block to "${thisBlock}"`, {
45+
elements: [thisSelected],
3546
})
3647
})
3748
.catch(err => {
38-
$error = err.message
49+
error?.set(err.message)
3950
})
4051
}
4152
})
53+
54+
onDestroy(() => {
55+
unsubs.forEach(u => u())
56+
})
4257
</script>
4358

44-
<p class="panel_toolbar_label label">
45-
{translate('panel.vanilla_block_display.title')}
46-
</p>
59+
{#if selected}
60+
<p class="panel_toolbar_label label">
61+
{translate('panel.vanilla_block_display.title')}
62+
</p>
4763

48-
<div class="toolbar custom-toolbar" title={translate('panel.vanilla_block_display.description')}>
49-
<div class="content" style="width: 95%;">
50-
<input type="text" bind:value={block} />
64+
<div
65+
class="toolbar custom-toolbar"
66+
title={translate('panel.vanilla_block_display.description')}
67+
>
68+
<div class="content" style="width: 95%;">
69+
<input type="text" bind:value={block} />
70+
</div>
5171
</div>
52-
</div>
5372

54-
{#if $error}
55-
<div class="error">
56-
{$error}
57-
</div>
73+
{#if $error}
74+
<div class="error">
75+
{$error}
76+
</div>
77+
{/if}
5878
{/if}
5979

6080
<style>
Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,24 @@
11
import { registerProjectPatch } from 'blockbench-patch-manager'
22
import { injectComponent } from 'svelte-patching-tools'
33
import { BLUEPRINT_FORMAT_ID } from '../../formats/blueprint'
4-
import { VanillaBlockDisplay } from '../../outliner/vanillaBlockDisplay'
5-
import EVENTS from '../../util/events'
64
import VanillaBlockDisplayElementPanel from './vanillaBlockDisplayElement.svelte'
75

8-
let unmountCallback: (() => Promise<void>) | null = null
9-
let currentUpdatePromise: Promise<void> | null = null
10-
11-
const updatePanel = () => {
12-
if (currentUpdatePromise) {
13-
return currentUpdatePromise.then(() => {
14-
void updatePanel()
15-
})
16-
}
17-
18-
currentUpdatePromise = new Promise(async resolve => {
19-
await unmountCallback?.()
20-
21-
const blockDisplay = VanillaBlockDisplay.selected.at(0)
22-
if (blockDisplay) {
23-
unmountCallback = injectComponent({
24-
component: VanillaBlockDisplayElementPanel,
25-
props: { selected: blockDisplay },
26-
elementSelector() {
27-
return Panels.element.node
28-
},
29-
postMount() {
30-
currentUpdatePromise = null
31-
resolve()
32-
},
33-
})
34-
} else {
35-
currentUpdatePromise = null
36-
resolve()
37-
}
38-
})
39-
}
40-
416
registerProjectPatch({
427
id: 'animated_java:append-element-panel/vanilla-block-display',
438

449
condition: ({ project }) => project.format.id === BLUEPRINT_FORMAT_ID,
4510

4611
apply: () => {
47-
const unsubscribers = [
48-
EVENTS.UNDO.subscribe(updatePanel),
49-
EVENTS.REDO.subscribe(updatePanel),
50-
EVENTS.UPDATE_SELECTION.subscribe(updatePanel),
51-
]
52-
return { unsubscribers }
12+
const unmountCallback = injectComponent({
13+
component: VanillaBlockDisplayElementPanel,
14+
elementSelector() {
15+
return Panels.element.node
16+
},
17+
})
18+
return { unmountCallback }
5319
},
5420

55-
revert: ({ unsubscribers }) => {
56-
unsubscribers.forEach(u => u())
21+
revert: async ({ unmountCallback }) => {
22+
await unmountCallback?.()
5723
},
5824
})

src/panels/vanillaItemDisplayElement/vanillaItemDisplayElement.svelte

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,88 @@
11
<script lang="ts" module>
2+
import { onDestroy } from 'svelte'
23
import { VanillaItemDisplay } from '../../outliner/vanillaItemDisplay'
4+
import EVENTS from '../../util/events'
35
import { localize as translate } from '../../util/lang'
4-
import { validateItem } from '../../util/minecraftUtil'
5-
import { ITEM_DISPLAY_ITEM_DISPLAY_SELECT } from './vanillaItemDisplayElement'
6+
import {
7+
ITEM_DISPLAY_ITEM_DISPLAY_SELECT,
8+
updateItemDisplaySelect,
9+
} from './vanillaItemDisplayElement'
610
</script>
711

812
<script lang="ts">
9-
export let selected: VanillaItemDisplay
13+
import { validateItem } from '../../util/minecraftUtil'
1014
11-
let item = selected.item
12-
let error = selected.error
15+
let selected = $state(VanillaItemDisplay.selected.at(0))
16+
let item = $derived(selected?.item)
17+
let error = $derived(selected?.error)
18+
19+
const onSelectionChanged = () => {
20+
selected = VanillaItemDisplay.selected.at(0)
21+
item = selected?.item
22+
error = selected?.error
23+
updateItemDisplaySelect()
24+
}
1325
14-
ITEM_DISPLAY_ITEM_DISPLAY_SELECT.set(selected.itemDisplay)
26+
const unsubs = [
27+
EVENTS.UNDO.subscribe(onSelectionChanged),
28+
EVENTS.REDO.subscribe(onSelectionChanged),
29+
EVENTS.UPDATE_SELECTION.subscribe(onSelectionChanged),
30+
]
1531
16-
$: {
17-
$error = ''
18-
if (selected.item !== item) {
19-
void validateItem(item)
32+
$effect(() => {
33+
const thisSelected = selected
34+
const thisItem = item
35+
error?.set('')
36+
if (thisSelected && thisItem && thisSelected.item !== thisItem) {
37+
void validateItem(thisItem)
2038
.then(err => {
2139
if (err) {
22-
$error = err
40+
error?.set(err)
2341
console.log('Item validation error:', err)
2442
return
2543
}
26-
console.log('Changing item to', item)
27-
Undo.initEdit({ elements: [selected] })
44+
console.log('Changing item to', thisItem)
45+
Undo.initEdit({ elements: [thisSelected] })
2846
29-
selected.item = item
47+
thisSelected.item = thisItem
3048
Project!.saved = false
3149
32-
Undo.finishEdit(`Change Item Display Item to "${item}"`, {
33-
elements: [selected],
50+
Undo.finishEdit(`Change Item Display Item to "${thisItem}"`, {
51+
elements: [thisSelected],
3452
})
3553
})
3654
.catch(err => {
37-
$error = err.message
55+
error?.set(err.message)
3856
})
3957
}
40-
}
58+
})
4159
4260
const mountItemDisplaySelect = (node: HTMLDivElement) => {
4361
node.appendChild(ITEM_DISPLAY_ITEM_DISPLAY_SELECT.node)
4462
}
63+
64+
onDestroy(() => {
65+
unsubs.forEach(u => u())
66+
})
4567
</script>
4668

47-
<p class="panel_toolbar_label label">
48-
{translate('panel.vanilla_item_display.title')}
49-
</p>
69+
{#if selected}
70+
<p class="panel_toolbar_label label">
71+
{translate('panel.vanilla_item_display.title')}
72+
</p>
5073

51-
<div class="toolbar custom-toolbar" title={translate('panel.vanilla_item_display.description')}>
52-
<div class="content" style="width: 95%;">
53-
<input type="text" bind:value={item} />
74+
<div class="toolbar custom-toolbar" title={translate('panel.vanilla_item_display.description')}>
75+
<div class="content" style="width: 95%;">
76+
<input type="text" bind:value={item} />
77+
</div>
78+
<div class="content" use:mountItemDisplaySelect></div>
5479
</div>
55-
<div class="content" use:mountItemDisplaySelect></div>
56-
</div>
5780

58-
{#if $error}
59-
<div class="error">
60-
{$error}
61-
</div>
81+
{#if $error}
82+
<div class="error">
83+
{$error}
84+
</div>
85+
{/if}
6286
{/if}
6387

6488
<style>

0 commit comments

Comments
 (0)