minecraft-renderer 0.1.106 → 0.1.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lightOwnerWorker.js +9 -0
- package/dist/lightOwnerWorker.js.map +7 -0
- package/dist/mesher.js +1 -1
- package/dist/mesher.js.map +2 -2
- package/dist/mesherWasm.js +222 -222
- package/dist/minecraft-renderer.js +105 -76
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +537 -508
- package/package.json +1 -1
- package/src/bundler/bundlePrepare.test.ts +25 -0
- package/src/bundler/bundlePrepare.ts +1 -1
- package/src/graphicsBackend/appViewer.ts +15 -0
- package/src/graphicsBackend/config.ts +8 -0
- package/src/graphicsBackend/rendererDefaultOptions.test.ts +51 -0
- package/src/graphicsBackend/rendererDefaultOptions.ts +18 -1
- package/src/graphicsBackend/rendererOptionsSync.ts +4 -3
- package/src/lib/blockEntityLightRegistry.ts +4 -0
- package/src/lib/skyLight.ts +17 -0
- package/src/lib/worldrendererCommon.lightOwner.test.ts +916 -0
- package/src/lib/worldrendererCommon.removeColumn.test.ts +16 -0
- package/src/lib/worldrendererCommon.ts +340 -67
- package/src/lighting/cache/rendererLightCache.test.ts +158 -0
- package/src/lighting/cache/rendererLightCache.ts +248 -0
- package/src/lighting/coordinator/clientLightCoordinator.test.ts +102 -0
- package/src/lighting/coordinator/clientLightCoordinator.ts +574 -0
- package/src/lighting/debug/clientLightProbe.test.ts +24 -0
- package/src/lighting/debug/clientLightProbe.ts +20 -0
- package/src/lighting/debug/clientLightTrace.test.ts +271 -0
- package/src/lighting/debug/clientLightTrace.ts +335 -0
- package/src/lighting/entity/entityLightController.test.ts +216 -0
- package/src/lighting/entity/entityLightController.ts +322 -0
- package/src/lighting/owner/clientLightOwner.test.ts +467 -0
- package/src/lighting/owner/clientLightOwner.ts +523 -0
- package/src/lighting/owner/lightOwnerHost.test.ts +78 -0
- package/src/lighting/owner/lightOwnerHost.ts +202 -0
- package/src/lighting/owner/lightOwnerWorker.ts +154 -0
- package/src/lighting/owner/updateLight1171OwnerPath.test.ts +68 -0
- package/src/lighting/owner/updateLightToOwnerEvents.ts +49 -0
- package/src/lighting/tables/lightTables1171.generated.json +10 -0
- package/src/lighting/tables/lightTables1171.test.ts +168 -0
- package/src/lighting/tables/lightTables1171.ts +59 -0
- package/src/lighting/versioning/clientLightVersions.test.ts +241 -0
- package/src/lighting/versioning/clientLightVersions.ts +203 -0
- package/src/lighting/versioning/pendingSectionFlush.test.ts +214 -0
- package/src/lighting/versioning/pendingSectionFlush.ts +123 -0
- package/src/mesher-shared/lightNibblePack.ts +26 -0
- package/src/mesher-shared/mcDataWorkerShim.cjs +9 -7
- package/src/mesher-shared/modelsGeometryCommon.test.ts +6 -1
- package/src/mesher-shared/shared.ts +48 -1
- package/src/three/chunkMeshManager.ts +26 -0
- package/src/three/entities.ts +97 -8
- package/src/three/entity/EntityMesh.ts +1 -0
- package/src/three/entity/legWalkAnimation.test.ts +154 -0
- package/src/three/entity/legWalkAnimation.ts +193 -0
- package/src/three/globalBlockBuffer.ts +94 -2
- package/src/three/globalLegacyBuffer.ts +94 -2
- package/src/three/graphicsBackendBase.ts +2 -9
- package/src/three/modules/clouds.ts +191 -0
- package/src/three/modules/index.ts +4 -0
- package/src/three/modules/sunMoon.ts +151 -0
- package/src/three/skyboxRenderer.ts +15 -8
- package/src/three/tests/clouds.test.ts +59 -0
- package/src/three/tests/globalBlockBuffer.test.ts +98 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +108 -0
- package/src/three/tests/waterFog.test.ts +25 -0
- package/src/three/waterFog.ts +28 -0
- package/src/three/worldRendererThree.ts +84 -39
- package/src/wasm-mesher/bridge/render-from-wasm.ts +46 -1
- package/src/wasm-mesher/runtime-build/wasm_mesher.d.ts +31 -5
- package/src/wasm-mesher/runtime-build/wasm_mesher.js +180 -5
- package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm +0 -0
- package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm.d.ts +11 -0
- package/src/wasm-mesher/tests/mesherLightDependencies.test.ts +83 -0
- package/src/wasm-mesher/tests/mesherWasmColumnTickSelect.test.ts +39 -0
- package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +30 -1
- package/src/wasm-mesher/tests/mesherWasmTickParseCache.test.ts +73 -0
- package/src/wasm-mesher/tests/mesherWasmTickSchedule.test.ts +51 -0
- package/src/wasm-mesher/tests/mesherWasmTopologyPostCache.test.ts +78 -0
- package/src/wasm-mesher/worker/clientLightDarkPublication.probe.test.ts +32 -0
- package/src/wasm-mesher/worker/mesherLightDependencies.ts +43 -0
- package/src/wasm-mesher/worker/mesherWasm.ownerLightSync.test.ts +198 -0
- package/src/wasm-mesher/worker/mesherWasm.ts +506 -96
- package/src/wasm-mesher/worker/mesherWasmChunkBuffer.ts +1 -0
- package/src/wasm-mesher/worker/mesherWasmColumnTickSelect.ts +47 -0
- package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +16 -5
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +17 -1
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +10 -0
- package/src/wasm-mesher/worker/mesherWasmLightMerge.test.ts +208 -0
- package/src/wasm-mesher/worker/mesherWasmLightMerge.ts +228 -0
- package/src/wasm-mesher/worker/mesherWasmOwnerLight.test.ts +161 -0
- package/src/wasm-mesher/worker/mesherWasmOwnerLight.ts +112 -0
- package/src/wasm-mesher/worker/mesherWasmTickParseCache.ts +45 -0
- package/src/wasm-mesher/worker/mesherWasmTickSchedule.ts +44 -0
- package/src/wasm-mesher/worker/mesherWasmTopologyPostCache.ts +63 -0
- package/src/worldView/types.ts +3 -0
- package/src/worldView/worldView.geometryReload.test.ts +68 -0
- package/src/worldView/worldView.spiral.test.ts +1 -1
- package/src/worldView/worldView.ts +49 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { describe, it, expect } from 'vitest'
|
|
3
|
+
import { applyOwnerPublicationToColumnCaches } from './mesherWasmOwnerLight'
|
|
4
|
+
import { displayLightColumn } from './mesherWasmLightMerge'
|
|
5
|
+
|
|
6
|
+
describe('dark publication omission diagnostic (current behavior)', () => {
|
|
7
|
+
const blockOnly = { sx: 0, sy: 0, sz: 0, blockLight: new Uint8Array(2048) }
|
|
8
|
+
const base = { worldMinY: 0, columnWorldX: 0, columnWorldZ: 0, numSections: 2 }
|
|
9
|
+
it('displays sky 15 when initial publication omits sky and no incoming light exists', () => {
|
|
10
|
+
const result = applyOwnerPublicationToColumnCaches({ ...base, incoming: undefined, display: undefined, sections: [blockOnly] })
|
|
11
|
+
expect(
|
|
12
|
+
displayLightColumn(result.display, 'sky')
|
|
13
|
+
.subarray(0, 4096)
|
|
14
|
+
.every(value => value === 15)
|
|
15
|
+
).toBe(true)
|
|
16
|
+
})
|
|
17
|
+
it('retains dark sky when an incoming authoritative cache exists', () => {
|
|
18
|
+
const initial = applyOwnerPublicationToColumnCaches({
|
|
19
|
+
...base,
|
|
20
|
+
incoming: undefined,
|
|
21
|
+
display: undefined,
|
|
22
|
+
sections: [{ ...blockOnly, skyLight: new Uint8Array(2048) }]
|
|
23
|
+
}).display
|
|
24
|
+
const result = applyOwnerPublicationToColumnCaches({ ...base, incoming: initial, display: initial, sections: [blockOnly] })
|
|
25
|
+
expect(
|
|
26
|
+
displayLightColumn(result.display, 'sky')
|
|
27
|
+
.subarray(0, 4096)
|
|
28
|
+
.every(value => value === 0)
|
|
29
|
+
).toBe(true)
|
|
30
|
+
expect(result.display).not.toBe(initial)
|
|
31
|
+
})
|
|
32
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Light-version stamp for one section mesh.
|
|
4
|
+
*
|
|
5
|
+
* Each column keeps only the latest applied owner version. The stamp is the
|
|
6
|
+
* newest of those versions whose sampled columns were actually meshed, and it
|
|
7
|
+
* stops before the first sampled column that was written but left out. The
|
|
8
|
+
* version requested on the dirty job is not an input.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export function sectionLightSampleColumns(sx: number, sz: number): string[] {
|
|
12
|
+
const columns: string[] = []
|
|
13
|
+
for (let dx = -16; dx <= 16; dx += 16) {
|
|
14
|
+
for (let dz = -16; dz <= 16; dz += 16) {
|
|
15
|
+
columns.push(`${sx + dx},${sz + dz}`)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return columns
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function provenMeshLightVersion(opts: {
|
|
22
|
+
sx: number
|
|
23
|
+
sz: number
|
|
24
|
+
usedColumns: ReadonlySet<string>
|
|
25
|
+
appliedVersionByColumn: ReadonlyMap<string, number>
|
|
26
|
+
}): number {
|
|
27
|
+
let gap = Number.POSITIVE_INFINITY
|
|
28
|
+
let covered = 0
|
|
29
|
+
for (const column of sectionLightSampleColumns(opts.sx, opts.sz)) {
|
|
30
|
+
const applied = opts.appliedVersionByColumn.get(column)
|
|
31
|
+
if (applied == null) continue
|
|
32
|
+
if (!opts.usedColumns.has(column)) gap = Math.min(gap, applied)
|
|
33
|
+
else covered = Math.max(covered, applied)
|
|
34
|
+
}
|
|
35
|
+
if (!Number.isFinite(gap)) return covered
|
|
36
|
+
let belowGap = 0
|
|
37
|
+
for (const column of sectionLightSampleColumns(opts.sx, opts.sz)) {
|
|
38
|
+
const applied = opts.appliedVersionByColumn.get(column)
|
|
39
|
+
if (applied == null || !opts.usedColumns.has(column) || applied >= gap) continue
|
|
40
|
+
belowGap = Math.max(belowGap, applied)
|
|
41
|
+
}
|
|
42
|
+
return belowGap
|
|
43
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import MinecraftData from 'minecraft-data'
|
|
3
|
+
import Chunks from 'prismarine-chunk'
|
|
4
|
+
import { Vec3 } from 'vec3'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import { packUnpackedLightSection } from '../../mesher-shared/lightNibblePack'
|
|
7
|
+
import { LIGHT_BLOCKS_PER_SECTION, maskBitSet, worldSectionMaskBit, type ParsedUpdateLight } from './mesherWasmLightMerge'
|
|
8
|
+
|
|
9
|
+
// Drives the real worker message handler. The legacy mesh path reads light
|
|
10
|
+
// through `World.getChannelLightNorm`, so that is what these tests observe.
|
|
11
|
+
|
|
12
|
+
const { parseUpdateLightV17 } = vi.hoisted(() => ({ parseUpdateLightV17: vi.fn() }))
|
|
13
|
+
|
|
14
|
+
vi.mock('../runtime-build/wasm_mesher.js', () => ({
|
|
15
|
+
default: vi.fn(async () => undefined),
|
|
16
|
+
parseUpdateLightV17
|
|
17
|
+
}))
|
|
18
|
+
vi.mock('../../mesher-shared/models', async importOriginal => ({
|
|
19
|
+
...(await importOriginal<object>()),
|
|
20
|
+
setBlockStatesData: vi.fn()
|
|
21
|
+
}))
|
|
22
|
+
vi.mock('./mesherWasmTickSchedule', () => ({
|
|
23
|
+
BULK_MESH_INTERVAL_MS: 50,
|
|
24
|
+
createMeshTickScheduler: () => ({ kick: vi.fn() })
|
|
25
|
+
}))
|
|
26
|
+
|
|
27
|
+
const VERSION = '1.17.1'
|
|
28
|
+
const NUM_SECTIONS = 16
|
|
29
|
+
const COLUMN_X = 16
|
|
30
|
+
const COLUMN_Z = 32
|
|
31
|
+
const PUBLISHED_Y = 64
|
|
32
|
+
const UNPUBLISHED_Y = 80
|
|
33
|
+
const PUBLISHED_POS = new Vec3(COLUMN_X + 3, PUBLISHED_Y + 1, COLUMN_Z + 5)
|
|
34
|
+
const UNPUBLISHED_POS = new Vec3(COLUMN_X + 3, UNPUBLISHED_Y + 5, COLUMN_Z + 5)
|
|
35
|
+
const INCOMING = {
|
|
36
|
+
[PUBLISHED_Y]: { sky: 3, block: 1 },
|
|
37
|
+
[UNPUBLISHED_Y]: { sky: 9, block: 4 }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type WorkerSelf = { onmessage: (event: { data: unknown }) => void }
|
|
41
|
+
type WorldLike = {
|
|
42
|
+
getColumn: (
|
|
43
|
+
x: number,
|
|
44
|
+
z: number
|
|
45
|
+
) => {
|
|
46
|
+
setSkyLight: (pos: Vec3, light: number) => void
|
|
47
|
+
setBlockLight: (pos: Vec3, light: number) => void
|
|
48
|
+
skyLightSections: Array<unknown | null>
|
|
49
|
+
blockLightSections: Array<unknown | null>
|
|
50
|
+
}
|
|
51
|
+
getChannelLightNorm: (pos: Vec3) => { block: number; sky: number }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const send = (data: unknown) => (globalThis.self as unknown as WorkerSelf).onmessage({ data })
|
|
55
|
+
const world = () => (globalThis as unknown as { world: WorldLike }).world
|
|
56
|
+
const lightAt = (pos: Vec3) => world().getChannelLightNorm(pos)
|
|
57
|
+
const expectedLight = ({ sky, block }: { sky: number; block: number }) => ({
|
|
58
|
+
sky: Math.min(15, sky + 2) / 15,
|
|
59
|
+
block: Math.min(15, block + 2) / 15
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
function serverColumnJson() {
|
|
63
|
+
const Chunk = Chunks(VERSION) as any
|
|
64
|
+
const chunk = new Chunk(undefined as any)
|
|
65
|
+
const stone = MinecraftData(VERSION).blocksByName.stone!.defaultState
|
|
66
|
+
chunk.setBlockStateId(new Vec3(3, PUBLISHED_POS.y, 5), stone)
|
|
67
|
+
chunk.setBlockStateId(new Vec3(3, UNPUBLISHED_POS.y, 5), stone)
|
|
68
|
+
return chunk.toJson()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function serverLightPacket(): ParsedUpdateLight {
|
|
72
|
+
const columnBytes = NUM_SECTIONS * LIGHT_BLOCKS_PER_SECTION
|
|
73
|
+
const skyLight = new Uint8Array(columnBytes)
|
|
74
|
+
const blockLight = new Uint8Array(columnBytes)
|
|
75
|
+
const skyLightMask = new Uint32Array(2)
|
|
76
|
+
const blockLightMask = new Uint32Array(2)
|
|
77
|
+
for (const [sectionY, light] of Object.entries(INCOMING)) {
|
|
78
|
+
const sectionIndex = Number(sectionY) / 16
|
|
79
|
+
const start = sectionIndex * LIGHT_BLOCKS_PER_SECTION
|
|
80
|
+
skyLight.fill(light.sky, start, start + LIGHT_BLOCKS_PER_SECTION)
|
|
81
|
+
blockLight.fill(light.block, start, start + LIGHT_BLOCKS_PER_SECTION)
|
|
82
|
+
maskBitSet(skyLightMask, worldSectionMaskBit(sectionIndex))
|
|
83
|
+
maskBitSet(blockLightMask, worldSectionMaskBit(sectionIndex))
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
x: COLUMN_X / 16,
|
|
87
|
+
z: COLUMN_Z / 16,
|
|
88
|
+
trustEdges: true,
|
|
89
|
+
numSections: NUM_SECTIONS,
|
|
90
|
+
skyLight,
|
|
91
|
+
blockLight,
|
|
92
|
+
skyLightMask,
|
|
93
|
+
blockLightMask,
|
|
94
|
+
emptySkyLightMask: new Uint32Array(2),
|
|
95
|
+
emptyBlockLightMask: new Uint32Array(2)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function publishOwnerLight(publicationVersion: number, sectionY: number, light: { sky: number; block: number }) {
|
|
100
|
+
const packed = (value: number) => packUnpackedLightSection(new Uint8Array(LIGHT_BLOCKS_PER_SECTION).fill(value))
|
|
101
|
+
send({
|
|
102
|
+
type: 'applyOwnerLightPublication',
|
|
103
|
+
worldGeneration: 1,
|
|
104
|
+
publicationVersion,
|
|
105
|
+
sections: [{ sx: COLUMN_X, sy: sectionY, sz: COLUMN_Z, blockLight: packed(light.block), skyLight: packed(light.sky) }]
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Moves the JS column away from the caches, so a sync of this section is detectable. */
|
|
110
|
+
function markUnpublishedSectionInJsColumn(light: { sky: number; block: number }) {
|
|
111
|
+
const column = world().getColumn(COLUMN_X, COLUMN_Z)
|
|
112
|
+
const local = new Vec3(UNPUBLISHED_POS.x & 15, UNPUBLISHED_POS.y, UNPUBLISHED_POS.z & 15)
|
|
113
|
+
column.setSkyLight(local, light.sky)
|
|
114
|
+
column.setBlockLight(local, light.block)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
describe('mesher worker JS column light with the client light owner', () => {
|
|
118
|
+
beforeEach(async () => {
|
|
119
|
+
vi.resetModules()
|
|
120
|
+
parseUpdateLightV17.mockReset()
|
|
121
|
+
parseUpdateLightV17.mockReturnValue(serverLightPacket())
|
|
122
|
+
vi.stubGlobal('self', {})
|
|
123
|
+
vi.stubGlobal('postMessage', vi.fn())
|
|
124
|
+
const realSetInterval = globalThis.setInterval
|
|
125
|
+
vi.stubGlobal('setInterval', vi.fn())
|
|
126
|
+
await import('./mesherWasm')
|
|
127
|
+
vi.stubGlobal('setInterval', realSetInterval)
|
|
128
|
+
|
|
129
|
+
send({ type: 'mesherData', config: { version: VERSION, worldMinY: 0, worldMaxY: 256, enableLighting: true } })
|
|
130
|
+
send({ type: 'chunk', x: COLUMN_X, z: COLUMN_Z, chunk: serverColumnJson() })
|
|
131
|
+
send({ type: 'setUpdateLightV17', rawPacket: new Uint8Array(1), numSections: NUM_SECTIONS })
|
|
132
|
+
await vi.waitFor(() => expect(parseUpdateLightV17).toHaveBeenCalledOnce())
|
|
133
|
+
|
|
134
|
+
expect(lightAt(PUBLISHED_POS)).toEqual(expectedLight(INCOMING[PUBLISHED_Y]))
|
|
135
|
+
expect(lightAt(UNPUBLISHED_POS)).toEqual(expectedLight(INCOMING[UNPUBLISHED_Y]))
|
|
136
|
+
}, 30_000)
|
|
137
|
+
|
|
138
|
+
afterEach(() => {
|
|
139
|
+
vi.unstubAllGlobals()
|
|
140
|
+
delete (globalThis as any).world
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('keeps authoritative zero light explicit in initially null sections', () => {
|
|
144
|
+
const sectionY = 96
|
|
145
|
+
const pos = new Vec3(COLUMN_X + 3, sectionY + 1, COLUMN_Z + 5)
|
|
146
|
+
expect(lightAt(pos)).toEqual({ block: 0, sky: 1 })
|
|
147
|
+
publishOwnerLight(1, sectionY, { sky: 0, block: 0 })
|
|
148
|
+
expect(lightAt(pos)).toEqual(expectedLight({ sky: 0, block: 0 }))
|
|
149
|
+
send({ type: 'chunk', x: COLUMN_X, z: COLUMN_Z, chunk: serverColumnJson() })
|
|
150
|
+
expect(lightAt(pos)).toEqual(expectedLight({ sky: 0, block: 0 }))
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('allocates only the authoritative channel and leaves omitted sections null', () => {
|
|
154
|
+
const sectionY = 96
|
|
155
|
+
send({
|
|
156
|
+
type: 'applyOwnerLightPublication',
|
|
157
|
+
worldGeneration: 1,
|
|
158
|
+
publicationVersion: 1,
|
|
159
|
+
sections: [{ sx: COLUMN_X, sy: sectionY, sz: COLUMN_Z, blockLight: new Uint8Array(2048) }]
|
|
160
|
+
})
|
|
161
|
+
const column = world().getColumn(COLUMN_X, COLUMN_Z)
|
|
162
|
+
expect(column.blockLightSections[sectionY / 16 + 1]).not.toBeNull()
|
|
163
|
+
expect(column.skyLightSections[sectionY / 16 + 1]).toBeNull()
|
|
164
|
+
expect(column.blockLightSections[sectionY / 16 + 2]).toBeNull()
|
|
165
|
+
expect(column.skyLightSections[sectionY / 16 + 2]).toBeNull()
|
|
166
|
+
expect(lightAt(new Vec3(COLUMN_X + 3, sectionY + 17, COLUMN_Z + 5))).toEqual({ block: 0, sky: 1 })
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('raises JS light when a publication brightens a section', () => {
|
|
170
|
+
const bright = { sky: 12, block: 7 }
|
|
171
|
+
publishOwnerLight(1, PUBLISHED_Y, bright)
|
|
172
|
+
expect(lightAt(PUBLISHED_POS)).toEqual(expectedLight(bright))
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('lowers JS light when a later publication darkens the section', () => {
|
|
176
|
+
const dark = { sky: 0, block: 0 }
|
|
177
|
+
publishOwnerLight(1, PUBLISHED_Y, { sky: 12, block: 7 })
|
|
178
|
+
publishOwnerLight(2, PUBLISHED_Y, dark)
|
|
179
|
+
expect(lightAt(PUBLISHED_POS)).toEqual(expectedLight(dark))
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('writes only the published section Ys into the JS column', () => {
|
|
183
|
+
const marker = { sky: 14, block: 13 }
|
|
184
|
+
const bright = { sky: 12, block: 7 }
|
|
185
|
+
markUnpublishedSectionInJsColumn(marker)
|
|
186
|
+
publishOwnerLight(1, PUBLISHED_Y, bright)
|
|
187
|
+
expect(lightAt(PUBLISHED_POS)).toEqual(expectedLight(bright))
|
|
188
|
+
expect(lightAt(UNPUBLISHED_POS)).toEqual(expectedLight(marker))
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('restores every incoming section in the JS column on revert', () => {
|
|
192
|
+
publishOwnerLight(1, PUBLISHED_Y, { sky: 12, block: 7 })
|
|
193
|
+
markUnpublishedSectionInJsColumn({ sky: 14, block: 13 })
|
|
194
|
+
send({ type: 'revertOwnerLightToIncoming' })
|
|
195
|
+
expect(lightAt(PUBLISHED_POS)).toEqual(expectedLight(INCOMING[PUBLISHED_Y]))
|
|
196
|
+
expect(lightAt(UNPUBLISHED_POS)).toEqual(expectedLight(INCOMING[UNPUBLISHED_Y]))
|
|
197
|
+
})
|
|
198
|
+
})
|