prismarine-world 3.4.0 → 3.6.1
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/.github/dependabot.yml +14 -0
- package/docs/API.md +17 -0
- package/docs/HISTORY.md +12 -0
- package/examples/iterator.js +65 -7
- package/package.json +9 -8
- package/src/iterators.js +76 -11
- package/src/world.js +6 -3
- package/src/worldsync.js +19 -10
- package/test/iterator.test.js +17 -0
- package/test/raycast.test.js +1 -1
- package/test/test.js +5 -5
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: npm
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: daily
|
|
7
|
+
open-pull-requests-limit: 10
|
|
8
|
+
ignore:
|
|
9
|
+
- dependency-name: event-promise
|
|
10
|
+
versions:
|
|
11
|
+
- ">= 1.a, < 2"
|
|
12
|
+
- dependency-name: mkdirp
|
|
13
|
+
versions:
|
|
14
|
+
- ">= 1.a, < 2"
|
package/docs/API.md
CHANGED
|
@@ -179,3 +179,20 @@ It steps exactly 1 block at a time, returning the block coordinates and the face
|
|
|
179
179
|
#### next()
|
|
180
180
|
|
|
181
181
|
return null or the next position (Vec3)
|
|
182
|
+
|
|
183
|
+
### SpiralIterator2d (pos, maxDistance)
|
|
184
|
+
|
|
185
|
+
`pos` is Vec3
|
|
186
|
+
|
|
187
|
+
`maxDistance` is number
|
|
188
|
+
|
|
189
|
+
Iterates outwards along x and z axis in a cubic spiral. First position returned is the starting position. Every step is 1 step away form the previous and next point.
|
|
190
|
+
|
|
191
|
+
#### next()
|
|
192
|
+
|
|
193
|
+
return null or the next position (Vec3)
|
|
194
|
+
|
|
195
|
+
#### NUMBER_OF_POINTS
|
|
196
|
+
|
|
197
|
+
Number of points the iterator will return.
|
|
198
|
+
|
package/docs/HISTORY.md
CHANGED
package/examples/iterator.js
CHANGED
|
@@ -1,12 +1,70 @@
|
|
|
1
1
|
const Vec3 = require('vec3').Vec3
|
|
2
|
-
const { OctahedronIterator } = require('../index').iterators
|
|
2
|
+
const { ManhattanIterator, SpiralIterator2d, OctahedronIterator } = require('../index').iterators
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
console.info('Octahedron Iterator 3D:\n' + iterate3d(new OctahedronIterator(new Vec3(0, 0, 0), 2)))
|
|
5
|
+
console.info('ManhattanIterator Iterator:\n' + iterate2d(new ManhattanIterator(0, 0, 5)))
|
|
6
|
+
console.info('SpiralIterator2d Iterator:\n' + iterate2d(new SpiralIterator2d(new Vec3(0, 0, 0), 4)))
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
function iterate3d (iter) {
|
|
9
|
+
let n = iter.next()
|
|
10
|
+
const result = []
|
|
11
|
+
const size = 3
|
|
12
|
+
let counter = 0
|
|
13
|
+
for (let x = 0; x < size * 2; x++) {
|
|
14
|
+
for (let y = 0; y < size * 2; y++) {
|
|
15
|
+
if (!result[x]) result[x] = []
|
|
16
|
+
for (let z = 0; z < size * 2; z++) {
|
|
17
|
+
if (!result[x][y]) result[x][y] = []
|
|
18
|
+
result[x][y][z] = ' '
|
|
19
|
+
}
|
|
20
|
+
}
|
|
10
21
|
}
|
|
11
|
-
console.
|
|
22
|
+
console.info(result)
|
|
23
|
+
while (n) {
|
|
24
|
+
result[n.x + size][n.y + size][n.z + size] = pad(counter)
|
|
25
|
+
counter = counter + 1
|
|
26
|
+
n = iter.next()
|
|
27
|
+
}
|
|
28
|
+
let str = 'Layer 0: ...\n'
|
|
29
|
+
for (let x = 0; x < size * 2; x++) {
|
|
30
|
+
let line = ''
|
|
31
|
+
for (let y = 0; y < size * 2; y++) {
|
|
32
|
+
for (let z = 0; z < size * 2; z++) {
|
|
33
|
+
line += '|' + pad(result[x][y][z])
|
|
34
|
+
}
|
|
35
|
+
line += ' '
|
|
36
|
+
}
|
|
37
|
+
str += line + '\n'
|
|
38
|
+
}
|
|
39
|
+
return str
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function iterate2d (iter) {
|
|
43
|
+
let n = iter.next()
|
|
44
|
+
const result = []
|
|
45
|
+
const size = 5
|
|
46
|
+
let counter = 0
|
|
47
|
+
for (let x = 0; x < size * 2; x++) {
|
|
48
|
+
for (let z = 0; z < size * 2; z++) {
|
|
49
|
+
if (!result[x]) result[x] = []
|
|
50
|
+
result[x][z] = ' '
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
while (n) {
|
|
54
|
+
result[n.x + size][n.z + size] = pad(counter)
|
|
55
|
+
counter = counter + 1
|
|
56
|
+
n = iter.next()
|
|
57
|
+
}
|
|
58
|
+
let str = ''
|
|
59
|
+
for (let x = 0; x < size * 2; x++) {
|
|
60
|
+
for (let z = 0; z < size * 2; z++) {
|
|
61
|
+
str += '|' + result[x][z]
|
|
62
|
+
}
|
|
63
|
+
str += '|\n'
|
|
64
|
+
}
|
|
65
|
+
return str
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function pad (num) {
|
|
69
|
+
return num.toString().padStart(3, ' ')
|
|
12
70
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prismarine-world",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"description": "The core implementation of the world for prismarine",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"pretest": "npm run lint",
|
|
8
8
|
"lint": "standard",
|
|
9
9
|
"fix": "standard --fix",
|
|
10
|
-
"test": "
|
|
10
|
+
"test": "mocha --reporter spec --exit"
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"game"
|
|
22
22
|
],
|
|
23
23
|
"engines": {
|
|
24
|
-
"
|
|
24
|
+
"node": ">=8.0.0"
|
|
25
25
|
},
|
|
26
26
|
"enginesStrict": true,
|
|
27
27
|
"author": "Will Franzen <wtfranzen@gmail.com> (http://will.xyz/)",
|
|
@@ -33,19 +33,20 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"buffer-equal": "^1.0.0",
|
|
35
35
|
"flatmap": "0.0.3",
|
|
36
|
-
"
|
|
37
|
-
"minecraft-data": "^2.47.0",
|
|
36
|
+
"minecraft-data": "^3.0.0",
|
|
38
37
|
"mkdirp": "^0.5.1",
|
|
39
38
|
"prismarine-chunk": "^1.14.0",
|
|
39
|
+
"prismarine-world": "file:.",
|
|
40
40
|
"prismarine-provider-anvil": "^2.0.0",
|
|
41
41
|
"prismarine-provider-raw": "^1.0.1",
|
|
42
|
+
"process": "^0.11.0",
|
|
42
43
|
"range": "0.0.3",
|
|
43
44
|
"rimraf": "^3.0.2",
|
|
44
45
|
"standard": "^16.0.1",
|
|
45
|
-
"
|
|
46
|
+
"expect": "^27.3.1",
|
|
47
|
+
"mocha": "^9.1.3"
|
|
46
48
|
},
|
|
47
49
|
"dependencies": {
|
|
48
|
-
"
|
|
49
|
-
"vec3": "~0.1.3"
|
|
50
|
+
"vec3": "^0.1.7"
|
|
50
51
|
}
|
|
51
52
|
}
|
package/src/iterators.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
const { Vec3 } = require('vec3')
|
|
2
2
|
|
|
3
|
+
const BlockFace = {
|
|
4
|
+
UNKNOWN: -999,
|
|
5
|
+
BOTTOM: 0,
|
|
6
|
+
TOP: 1,
|
|
7
|
+
NORTH: 2,
|
|
8
|
+
SOUTH: 3,
|
|
9
|
+
WEST: 4,
|
|
10
|
+
EAST: 5
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
// 2D spiral iterator, useful to iterate on
|
|
4
14
|
// columns that are centered on bot position
|
|
5
15
|
// https://en.wikipedia.org/wiki/Taxicab_geometry
|
|
6
16
|
class ManhattanIterator {
|
|
7
17
|
constructor (x, y, maxDistance) {
|
|
8
|
-
this.maxDistance = maxDistance
|
|
18
|
+
this.maxDistance = Math.floor(maxDistance)
|
|
9
19
|
this.startx = x
|
|
10
20
|
this.starty = y
|
|
11
21
|
this.x = 2
|
|
@@ -90,16 +100,6 @@ class OctahedronIterator {
|
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
const BlockFace = {
|
|
94
|
-
UNKNOWN: -999,
|
|
95
|
-
BOTTOM: 0,
|
|
96
|
-
TOP: 1,
|
|
97
|
-
NORTH: 2,
|
|
98
|
-
SOUTH: 3,
|
|
99
|
-
WEST: 4,
|
|
100
|
-
EAST: 5
|
|
101
|
-
}
|
|
102
|
-
|
|
103
103
|
// This iterate along a ray starting at `pos` in `dir` direction
|
|
104
104
|
// It steps exactly 1 block at a time, returning the block coordinates
|
|
105
105
|
// and the face by which the ray entered the block.
|
|
@@ -204,10 +204,75 @@ class RaycastIterator {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
class SpiralIterator2d {
|
|
208
|
+
/**
|
|
209
|
+
* Spiral outwards from a central position in growing squares.
|
|
210
|
+
* Every point has a constant distance to its previous and following position of 1. First point returned is the starting position.
|
|
211
|
+
* Generates positions like this:
|
|
212
|
+
* ```text
|
|
213
|
+
* 16 15 14 13 12
|
|
214
|
+
* 17 4 3 2 11
|
|
215
|
+
* 18 5 0 1 10
|
|
216
|
+
* 19 6 7 8 9
|
|
217
|
+
* 20 21 22 23 24
|
|
218
|
+
* (maxDistance = 2; points returned = 25)
|
|
219
|
+
* ```
|
|
220
|
+
* Copy and past warrior source: https://stackoverflow.com/questions/3706219/algorithm-for-iterating-over-an-outward-spiral-on-a-discrete-2d-grid-from-the-or
|
|
221
|
+
* @param {Vec3} pos Starting position
|
|
222
|
+
* @param {number} maxDistance Max distance from starting position
|
|
223
|
+
*/
|
|
224
|
+
constructor (pos, maxDistance) {
|
|
225
|
+
this.start = pos
|
|
226
|
+
this.maxDistance = maxDistance
|
|
227
|
+
|
|
228
|
+
this.NUMBER_OF_POINTS = Math.floor(Math.pow((Math.floor(maxDistance) - 0.5) * 2, 2))
|
|
229
|
+
|
|
230
|
+
// (di, dj) is a vector - direction in which we move right now
|
|
231
|
+
this.di = 1
|
|
232
|
+
this.dj = 0
|
|
233
|
+
// length of current segment
|
|
234
|
+
this.segment_length = 1
|
|
235
|
+
// current position (i, j) and how much of current segment we passed
|
|
236
|
+
this.i = 0
|
|
237
|
+
this.j = 0
|
|
238
|
+
this.segment_passed = 0
|
|
239
|
+
// current iteration
|
|
240
|
+
this.k = 0
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
next () {
|
|
244
|
+
if (this.k >= this.NUMBER_OF_POINTS) return null
|
|
245
|
+
const output = this.start.offset(this.i, 0, this.j)
|
|
246
|
+
|
|
247
|
+
// make a step, add 'direction' vector (di, dj) to current position (i, j)
|
|
248
|
+
this.i += this.di
|
|
249
|
+
this.j += this.dj
|
|
250
|
+
this.segment_passed += 1
|
|
251
|
+
|
|
252
|
+
if (this.segment_passed === this.segment_length) {
|
|
253
|
+
// done with current segment
|
|
254
|
+
this.segment_passed = 0
|
|
255
|
+
|
|
256
|
+
// 'rotate' directions
|
|
257
|
+
const buffer = this.di
|
|
258
|
+
this.di = -this.dj
|
|
259
|
+
this.dj = buffer
|
|
260
|
+
|
|
261
|
+
// increase segment length if necessary
|
|
262
|
+
if (this.dj === 0) {
|
|
263
|
+
this.segment_length += 1
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
this.k += 1
|
|
267
|
+
return output
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
207
271
|
module.exports = {
|
|
208
272
|
ManhattanIterator,
|
|
209
273
|
ManathanIterator: ManhattanIterator, // backward compatibility
|
|
210
274
|
OctahedronIterator,
|
|
211
275
|
RaycastIterator,
|
|
276
|
+
SpiralIterator2d,
|
|
212
277
|
BlockFace
|
|
213
278
|
}
|
package/src/world.js
CHANGED
|
@@ -2,7 +2,7 @@ const { Vec3 } = require('vec3')
|
|
|
2
2
|
const { EventEmitter } = require('events')
|
|
3
3
|
const { RaycastIterator } = require('./iterators')
|
|
4
4
|
const WorldSync = require('./worldsync')
|
|
5
|
-
const once = require('
|
|
5
|
+
const { once } = require('events')
|
|
6
6
|
|
|
7
7
|
function columnKeyXZ (chunkX, chunkZ) {
|
|
8
8
|
return chunkX + ',' + chunkZ
|
|
@@ -64,7 +64,6 @@ class World extends EventEmitter {
|
|
|
64
64
|
if (block && (!matcher || matcher(block))) {
|
|
65
65
|
const intersect = iter.intersect(block.shapes, position)
|
|
66
66
|
if (intersect) {
|
|
67
|
-
block.position = position
|
|
68
67
|
block.face = intersect.face
|
|
69
68
|
block.intersect = intersect.pos
|
|
70
69
|
return block
|
|
@@ -101,6 +100,8 @@ class World extends EventEmitter {
|
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
_emitBlockUpdate (oldBlock, newBlock, position) {
|
|
103
|
+
oldBlock.position = position.floored()
|
|
104
|
+
newBlock.position = oldBlock.position
|
|
104
105
|
this.emit('blockUpdate', oldBlock, newBlock)
|
|
105
106
|
this.emit(`blockUpdate:${position}`, oldBlock, newBlock)
|
|
106
107
|
}
|
|
@@ -202,7 +203,9 @@ class World extends EventEmitter {
|
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
async getBlock (pos) {
|
|
205
|
-
|
|
206
|
+
const block = (await this.getColumnAt(pos)).getBlock(posInChunk(pos))
|
|
207
|
+
block.position = pos.floored()
|
|
208
|
+
return block
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
async getBlockStateId (pos) {
|
package/src/worldsync.js
CHANGED
|
@@ -43,13 +43,18 @@ class WorldSync extends EventEmitter {
|
|
|
43
43
|
while (pos) {
|
|
44
44
|
const position = new Vec3(pos.x, pos.y, pos.z)
|
|
45
45
|
const block = this.getBlock(position)
|
|
46
|
-
if (block
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
if (block) {
|
|
47
|
+
if (matcher) {
|
|
48
|
+
if (matcher(block, iter)) {
|
|
49
|
+
return block
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
const intersect = iter.intersect(block.shapes, position)
|
|
53
|
+
if (intersect) {
|
|
54
|
+
block.face = intersect.face
|
|
55
|
+
block.intersect = intersect.pos
|
|
56
|
+
return block
|
|
57
|
+
}
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
pos = iter.next()
|
|
@@ -58,8 +63,10 @@ class WorldSync extends EventEmitter {
|
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
_emitBlockUpdate (oldBlock, newBlock, position) {
|
|
66
|
+
oldBlock.position = position.floored()
|
|
67
|
+
newBlock.position = oldBlock.position
|
|
61
68
|
this.emit('blockUpdate', oldBlock, newBlock)
|
|
62
|
-
|
|
69
|
+
this.emit(`blockUpdate:${position}`, oldBlock, newBlock)
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
unloadColumn (chunkX, chunkZ) {
|
|
@@ -91,7 +98,9 @@ class WorldSync extends EventEmitter {
|
|
|
91
98
|
getBlock (pos) {
|
|
92
99
|
const chunk = this.getColumnAt(pos)
|
|
93
100
|
if (!chunk) return null
|
|
94
|
-
|
|
101
|
+
const block = chunk.getBlock(posInChunk(pos))
|
|
102
|
+
block.position = pos.floored()
|
|
103
|
+
return block
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
getBlockStateId (pos) {
|
|
@@ -137,7 +146,7 @@ class WorldSync extends EventEmitter {
|
|
|
137
146
|
const oldBlock = chunk.getBlock(pInChunk)
|
|
138
147
|
chunk.setBlock(pInChunk, block)
|
|
139
148
|
this.async.saveAt(pos)
|
|
140
|
-
this._emitBlockUpdate(oldBlock, block)
|
|
149
|
+
this._emitBlockUpdate(oldBlock, block, pos)
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
setBlockStateId (pos, stateId) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
const { SpiralIterator2d } = require('../src/iterators')
|
|
4
|
+
const { Vec3 } = require('vec3')
|
|
5
|
+
const expect = require('expect')
|
|
6
|
+
|
|
7
|
+
describe('Spiral iterator', () => {
|
|
8
|
+
it('simple function test', async () => {
|
|
9
|
+
const startPos = new Vec3(0, 0, 0)
|
|
10
|
+
const iter = new SpiralIterator2d(startPos, 2)
|
|
11
|
+
const first = iter.next()
|
|
12
|
+
const second = iter.next()
|
|
13
|
+
|
|
14
|
+
expect(first.x === startPos.x && first.y === startPos.y && first.z === startPos.z).toBeTruthy()
|
|
15
|
+
expect(second.x === startPos.x && second.y === startPos.y && second.z === startPos.z).toBeFalsy()
|
|
16
|
+
})
|
|
17
|
+
})
|
package/test/raycast.test.js
CHANGED
package/test/test.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint-env
|
|
1
|
+
/* eslint-env mocha */
|
|
2
2
|
|
|
3
3
|
const flatMap = require('flatmap')
|
|
4
4
|
const range = require('range').range
|
|
@@ -28,11 +28,11 @@ describe('saving and loading works', function () {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const regionPath = 'world/testRegion'
|
|
31
|
-
|
|
31
|
+
before((cb) => {
|
|
32
32
|
mkdirp(regionPath, cb)
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
after(cb => {
|
|
36
36
|
rimraf(regionPath, cb)
|
|
37
37
|
})
|
|
38
38
|
|
|
@@ -87,11 +87,11 @@ describe('Synchronous saving and loading works', function () {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
const regionPath = 'world/testRegionSync'
|
|
90
|
-
|
|
90
|
+
before((cb) => {
|
|
91
91
|
mkdirp(regionPath, cb)
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
after(cb => {
|
|
95
95
|
rimraf(regionPath, cb)
|
|
96
96
|
})
|
|
97
97
|
|