prismarine-world 3.6.0 → 3.6.2

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.
@@ -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"
@@ -1,6 +1,3 @@
1
- # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2
- # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3
-
4
1
  name: CI
5
2
 
6
3
  on:
@@ -25,4 +22,4 @@ jobs:
25
22
  with:
26
23
  node-version: ${{ matrix.node-version }}
27
24
  - run: npm install
28
- - run: npm test
25
+ - run: npm test
@@ -13,13 +13,20 @@ jobs:
13
13
  - name: Set up Node.js
14
14
  uses: actions/setup-node@master
15
15
  with:
16
- node-version: 10.0.0
17
- - name: Publish if version has been updated
18
- uses: pascalgn/npm-publish-action@4f4bf159e299f65d21cd1cbd96fc5d53228036df
19
- with: # All of theses inputs are optional
20
- tag_name: "%s"
21
- tag_message: "%s"
22
- commit_pattern: "^Release (\\S+)"
23
- env: # More info about the environment variables in the README
24
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Leave this as is, it's automatically generated
25
- NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} # You need to set this in your repo settings
16
+ node-version: 14.0.0
17
+ - id: publish
18
+ uses: JS-DevTools/npm-publish@v1
19
+ with:
20
+ token: ${{ secrets.NPM_AUTH_TOKEN }}
21
+ - name: Create Release
22
+ if: steps.publish.outputs.type != 'none'
23
+ id: create_release
24
+ uses: actions/create-release@v1
25
+ env:
26
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27
+ with:
28
+ tag_name: ${{ steps.publish.outputs.version }}
29
+ release_name: Release ${{ steps.publish.outputs.version }}
30
+ body: ${{ steps.publish.outputs.version }}
31
+ draft: false
32
+ prerelease: false
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  [![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/prismarine-world)
10
10
 
11
- Provides a minecraft world: an infinite collection of 16x256x26 chunks.
11
+ Provides a minecraft world: an infinite collection of 16x256x16 chunks.
12
12
 
13
13
  ## Usage
14
14
 
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
@@ -1,5 +1,16 @@
1
1
  ## History
2
2
 
3
+ ### 3.6.2
4
+
5
+ * Fix chunk saving reference errors (@kf106 & @moonborrow) [#100](https://github.com/PrismarineJS/prismarine-world/pull/100)
6
+ * Fix typo in README.md (@takeru) [#108](https://github.com/PrismarineJS/prismarine-world/pull/108)
7
+ * Improved types (@TRCYX) [#99](https://github.com/PrismarineJS/prismarine-world/pull/99)
8
+ * Fix ManhattanIterator [#101](https://github.com/PrismarineJS/prismarine-world/pull/101) (@IceTank)
9
+
10
+ ### 3.6.1
11
+
12
+ * Update mcdata
13
+
3
14
  ### 3.6.0
4
15
 
5
16
  * Added match while check intersect (@sefirosweb)
@@ -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
- const iterator = new OctahedronIterator(new Vec3(0, 0, 0), 5)
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
- while (true) {
7
- const n = iterator.next()
8
- if (n === null) {
9
- break
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.log(n)
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,14 @@
1
1
  {
2
2
  "name": "prismarine-world",
3
- "version": "3.6.0",
3
+ "version": "3.6.2",
4
4
  "description": "The core implementation of the world for prismarine",
5
5
  "main": "index.js",
6
+ "types": "./types/index.d.ts",
6
7
  "scripts": {
7
8
  "pretest": "npm run lint",
8
9
  "lint": "standard",
9
10
  "fix": "standard --fix",
10
- "test": "jest --verbose"
11
+ "test": "mocha --reporter spec --exit"
11
12
  },
12
13
  "repository": {
13
14
  "type": "git",
@@ -21,7 +22,7 @@
21
22
  "game"
22
23
  ],
23
24
  "engines": {
24
- "nodejs": ">=8.0.0"
25
+ "node": ">=8.0.0"
25
26
  },
26
27
  "enginesStrict": true,
27
28
  "author": "Will Franzen <wtfranzen@gmail.com> (http://will.xyz/)",
@@ -32,17 +33,19 @@
32
33
  "homepage": "https://github.com/PrismarineJS/prismarine-world",
33
34
  "devDependencies": {
34
35
  "buffer-equal": "^1.0.0",
36
+ "expect": "^29.1.0",
35
37
  "flatmap": "0.0.3",
36
- "jest": "^26.0.1",
37
- "minecraft-data": "^2.47.0",
38
+ "minecraft-data": "^3.0.0",
38
39
  "mkdirp": "^0.5.1",
39
- "prismarine-chunk": "^1.14.0",
40
+ "mocha": "^10.0.0",
41
+ "prismarine-chunk": "^1.31.0",
40
42
  "prismarine-provider-anvil": "^2.0.0",
41
43
  "prismarine-provider-raw": "^1.0.1",
44
+ "prismarine-world": "file:.",
45
+ "process": "^0.11.0",
42
46
  "range": "0.0.3",
43
47
  "rimraf": "^3.0.2",
44
- "standard": "^16.0.1",
45
- "process": "^0.11.0"
48
+ "standard": "^17.0.0"
46
49
  },
47
50
  "dependencies": {
48
51
  "vec3": "^0.1.7"
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
@@ -14,11 +24,15 @@ class ManhattanIterator {
14
24
  this.leg = -1
15
25
  }
16
26
 
27
+ /**
28
+ * Returns the next position. If the iterator is at the end, returns null. Position will be 2d along the x z plane and y always being 0.
29
+ * @returns {Vec3 | null}
30
+ */
17
31
  next () {
18
32
  if (this.leg === -1) {
19
33
  // use -1 as the center
20
34
  this.leg = 0
21
- return { x: this.startx, y: this.starty }
35
+ return new Vec3(this.startx, 0, this.starty)
22
36
  } else if (this.leg === 0) {
23
37
  if (this.maxDistance === 1) return null
24
38
  this.x--
@@ -90,16 +104,6 @@ class OctahedronIterator {
90
104
  }
91
105
  }
92
106
 
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
107
  // This iterate along a ray starting at `pos` in `dir` direction
104
108
  // It steps exactly 1 block at a time, returning the block coordinates
105
109
  // and the face by which the ray entered the block.
@@ -204,10 +208,75 @@ class RaycastIterator {
204
208
  }
205
209
  }
206
210
 
211
+ class SpiralIterator2d {
212
+ /**
213
+ * Spiral outwards from a central position in growing squares.
214
+ * Every point has a constant distance to its previous and following position of 1. First point returned is the starting position.
215
+ * Generates positions like this:
216
+ * ```text
217
+ * 16 15 14 13 12
218
+ * 17 4 3 2 11
219
+ * 18 5 0 1 10
220
+ * 19 6 7 8 9
221
+ * 20 21 22 23 24
222
+ * (maxDistance = 2; points returned = 25)
223
+ * ```
224
+ * Copy and paste warrior source: https://stackoverflow.com/questions/3706219/algorithm-for-iterating-over-an-outward-spiral-on-a-discrete-2d-grid-from-the-or
225
+ * @param {Vec3} pos Starting position
226
+ * @param {number} maxDistance Max distance from starting position
227
+ */
228
+ constructor (pos, maxDistance) {
229
+ this.start = pos
230
+ this.maxDistance = maxDistance
231
+
232
+ this.NUMBER_OF_POINTS = Math.floor(Math.pow((Math.floor(maxDistance) - 0.5) * 2, 2))
233
+
234
+ // (di, dj) is a vector - direction in which we move right now
235
+ this.di = 1
236
+ this.dj = 0
237
+ // length of current segment
238
+ this.segment_length = 1
239
+ // current position (i, j) and how much of current segment we passed
240
+ this.i = 0
241
+ this.j = 0
242
+ this.segment_passed = 0
243
+ // current iteration
244
+ this.k = 0
245
+ }
246
+
247
+ next () {
248
+ if (this.k >= this.NUMBER_OF_POINTS) return null
249
+ const output = this.start.offset(this.i, 0, this.j)
250
+
251
+ // make a step, add 'direction' vector (di, dj) to current position (i, j)
252
+ this.i += this.di
253
+ this.j += this.dj
254
+ this.segment_passed += 1
255
+
256
+ if (this.segment_passed === this.segment_length) {
257
+ // done with current segment
258
+ this.segment_passed = 0
259
+
260
+ // 'rotate' directions
261
+ const buffer = this.di
262
+ this.di = -this.dj
263
+ this.dj = buffer
264
+
265
+ // increase segment length if necessary
266
+ if (this.dj === 0) {
267
+ this.segment_length += 1
268
+ }
269
+ }
270
+ this.k += 1
271
+ return output
272
+ }
273
+ }
274
+
207
275
  module.exports = {
208
276
  ManhattanIterator,
209
277
  ManathanIterator: ManhattanIterator, // backward compatibility
210
278
  OctahedronIterator,
211
279
  RaycastIterator,
280
+ SpiralIterator2d,
212
281
  BlockFace
213
282
  }
package/src/world.js CHANGED
@@ -16,7 +16,9 @@ class World extends EventEmitter {
16
16
  constructor (chunkGenerator, storageProvider = null, savingInterval = 1000) {
17
17
  super()
18
18
  this.savingQueue = new Map()
19
+ this.unloadQueue = new Map()
19
20
  this.finishedSaving = Promise.resolve()
21
+ this.currentlySaving = false // semaphore for saving
20
22
  this.columns = {}
21
23
  this.chunkGenerator = chunkGenerator
22
24
  this.storageProvider = storageProvider
@@ -123,6 +125,17 @@ class World extends EventEmitter {
123
125
 
124
126
  unloadColumn (chunkX, chunkZ) {
125
127
  const key = columnKeyXZ(chunkX, chunkZ)
128
+ if (this.storageProvider && this.savingQueue.has(key)) {
129
+ this.unloadQueue.set(key, { chunkX, chunkZ })
130
+ } else {
131
+ this.forceUnloadColumn(key, chunkX, chunkZ)
132
+ }
133
+ }
134
+
135
+ forceUnloadColumn (key, chunkX, chunkZ) {
136
+ if (this.unloadQueue.has(key)) {
137
+ this.unloadQueue.delete(key)
138
+ }
126
139
  delete this.columns[key]
127
140
  const columnCorner = new Vec3(chunkX * 16, 0, chunkZ * 16)
128
141
  this.emit('chunkColumnUnload', columnCorner)
@@ -136,15 +149,24 @@ class World extends EventEmitter {
136
149
  // interval. The set structure is maintaining the order of insertion
137
150
  for (const [key, { chunkX, chunkZ }] of this.savingQueue.entries()) {
138
151
  this.finishedSaving = Promise.all([this.finishedSaving,
139
- this.storageProvider.save(chunkX, chunkZ, this.columns[key])])
152
+ this.storageProvider.save(chunkX, chunkZ, this.columns[key])
153
+ ])
140
154
  }
155
+ await this.finishedSaving
141
156
  this.savingQueue.clear()
157
+ for (const [key, { chunkX, chunkZ }] of this.unloadQueue.entries()) {
158
+ this.forceUnloadColumn(key, chunkX, chunkZ)
159
+ }
142
160
  this.emit('doneSaving')
143
161
  }
144
162
 
145
163
  startSaving () {
146
164
  this.savingInt = setInterval(async () => {
147
- await this.saveNow()
165
+ if (this.currentlySaving === false) {
166
+ this.currentlySaving = true
167
+ await this.saveNow()
168
+ this.currentlySaving = false
169
+ }
148
170
  }, this.savingInterval)
149
171
  }
150
172
 
@@ -0,0 +1,39 @@
1
+ /* eslint-env mocha */
2
+
3
+ const { SpiralIterator2d, ManhattanIterator } = require('../src/iterators')
4
+ const { Vec3 } = require('vec3')
5
+ const expect = require('expect').default
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
+ })
18
+
19
+ describe('ManhattanIterator iterator', () => {
20
+ it('First position is same as start', () => {
21
+ const start = new Vec3(1, 2, 3)
22
+ const iter = new ManhattanIterator(start.x, start.z, 5)
23
+ const first = iter.next()
24
+ expect(first.x === start.x && first.z === start.z).toBeTruthy()
25
+ })
26
+
27
+ it('Sample positions match', () => {
28
+ const start = new Vec3(1, 2, 3)
29
+ const iter = new ManhattanIterator(start.x, start.z, 5)
30
+ const sample = [new Vec3(1, 0, 3), new Vec3(2, 0, 3), new Vec3(1, 0, 4), new Vec3(0, 0, 3)]
31
+ let counter = 0
32
+ let next = iter.next()
33
+ while (next && counter < sample.length) {
34
+ expect(next.x === sample[counter].x && next.z === sample[counter].z).toBeTruthy()
35
+ next = iter.next()
36
+ counter++
37
+ }
38
+ })
39
+ })
@@ -1,4 +1,4 @@
1
- /* eslint-env jest */
1
+ /* eslint-env mocha */
2
2
 
3
3
  const World = require('prismarine-world')('1.16.4')
4
4
  const Chunk = require('prismarine-chunk')('1.16.4')
package/test/test.js CHANGED
@@ -1,4 +1,4 @@
1
- /* eslint-env jest */
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
- beforeAll((cb) => {
31
+ before((cb) => {
32
32
  mkdirp(regionPath, cb)
33
33
  })
34
34
 
35
- afterAll(cb => {
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
- beforeAll((cb) => {
90
+ before((cb) => {
91
91
  mkdirp(regionPath, cb)
92
92
  })
93
93
 
94
- afterAll(cb => {
94
+ after(cb => {
95
95
  rimraf(regionPath, cb)
96
96
  })
97
97
 
@@ -0,0 +1,10 @@
1
+ import { World } from "./world";
2
+
3
+ export * as iterators from "./iterators";
4
+
5
+ // Make public the types related to World, but not the classes
6
+ // (since they aren't exported in js)
7
+ import type * as world from "./world";
8
+ export { world };
9
+
10
+ export default function loader(mcVersion: string): typeof World;
@@ -0,0 +1,145 @@
1
+ import type { Vec3 } from "vec3";
2
+
3
+ export declare enum BlockFace {
4
+ UNKNOWN = -999,
5
+ BOTTOM = 0,
6
+ TOP = 1,
7
+ NORTH = 2,
8
+ SOUTH = 3,
9
+ WEST = 4,
10
+ EAST = 5,
11
+ }
12
+
13
+ export type RaycastBlock = {
14
+ x: number;
15
+ y: number;
16
+ z: number;
17
+ face: BlockFace;
18
+ };
19
+
20
+ export type RaycastIntersection = {
21
+ pos: Vec3;
22
+ face: BlockFace;
23
+ };
24
+
25
+ /** [x0, y0, z0, x1, y1, z1] */
26
+ export type Shape = [number, number, number, number, number, number];
27
+
28
+ export interface Iterator<T> {
29
+ next(): T | null;
30
+ }
31
+
32
+ // 2D spiral iterator, useful to iterate on
33
+ // columns that are centered on bot position
34
+ // https://en.wikipedia.org/wiki/Taxicab_geometry
35
+ export declare class ManhattanIterator implements Iterator<Vec3> {
36
+ public readonly maxDistance: number;
37
+ public readonly startx: number;
38
+ public readonly starty: number;
39
+ private x: number;
40
+ private y: number;
41
+ private layer: number;
42
+ private leg: number;
43
+
44
+ constructor(x: number, y: number, maxDistance: number);
45
+
46
+ /**
47
+ * @returns {Vec3 | null} The current position of the iterator OR null if exceeded maxDistance.
48
+ */
49
+ next(): Vec3 | null;
50
+ }
51
+
52
+ export declare class OctahedronIterator implements Iterator<Vec3> {
53
+ public readonly start: Vec3;
54
+ public readonly maxDistance: number;
55
+ private apothem: number;
56
+ private x: number;
57
+ private y: number;
58
+ private z: number;
59
+ private L: number;
60
+ private R: number;
61
+
62
+ constructor(start: Vec3, maxDistance: number);
63
+
64
+ /**
65
+ * @returns {Vec3 | null} The current position of the iterator OR null if exceeded maxDistance.
66
+ */
67
+ next(): Vec3 | null;
68
+ }
69
+
70
+ // This iterate along a ray starting at `pos` in `dir` direction
71
+ // It steps exactly 1 block at a time, returning the block coordinates
72
+ // and the face by which the ray entered the block.
73
+ export declare class RaycastIterator implements Iterator<RaycastBlock> {
74
+ private block: RaycastBlock;
75
+ public readonly pos: Vec3;
76
+ public readonly dir: Vec3;
77
+ private invDirX: number;
78
+ private invDirY: number;
79
+ private invDirZ: number;
80
+ private stepX: number;
81
+ private stepY: number;
82
+ private stepZ: number;
83
+ private tDeltaX: number;
84
+ private tDeltaY: number;
85
+ private tDeltaZ: number;
86
+ private tMaxX: number;
87
+ private tMaxY: number;
88
+ private tMaxZ: number;
89
+ public readonly maxDistance: number;
90
+
91
+ constructor(pos: Vec3, dir: Vec3, distance: number);
92
+
93
+ /**
94
+ * @param {Shape[]} shapes Takes shapes from block.shapes.
95
+ * @param {Vec3} offset Offset from original position to start the intersect calculation from.
96
+ * @returns {RaycastIntersection | null} A possible intersection.
97
+ */
98
+ intersect(shapes: Shape[], offset: Vec3): RaycastIntersection | null;
99
+
100
+ /**
101
+ * @returns {RaycastBlock | null} The block the raycast is currently passing through (not hit detection, just the general AABB of a block if it were there).
102
+ */
103
+ next(): RaycastBlock | null;
104
+ }
105
+
106
+ /**
107
+ * Spiral outwards from a central position in growing squares.
108
+ * Every point has a constant distance to its previous and following position of 1. First point returned is the starting position.
109
+ * Generates positions like this:
110
+ * ```text
111
+ * 16 15 14 13 12
112
+ * 17 4 3 2 11
113
+ * 18 5 0 1 10
114
+ * 19 6 7 8 9
115
+ * 20 21 22 23 24
116
+ * (maxDistance = 2; points returned = 25)
117
+ * ```
118
+ * Copy and paste warrior source: https://stackoverflow.com/questions/3706219/algorithm-for-iterating-over-an-outward-spiral-on-a-discrete-2d-grid-from-the-or
119
+ */
120
+ export declare class SpiralIterator2d implements Iterator<Vec3> {
121
+ public readonly start: Vec3;
122
+ public readonly maxDistance: number;
123
+ private di: number;
124
+ private dj: number;
125
+ private i: number;
126
+ private j: number;
127
+ private k: number;
128
+ private segment_passed: number;
129
+ private segment_length: number;
130
+ private readonly NUMBER_OF_POINTS: number;
131
+
132
+ /**
133
+ * @param {Vec3} pos Starting position
134
+ * @param {number} maxDistance Max distance from starting position
135
+ */
136
+ constructor(pos: Vec3, maxDistance: number);
137
+
138
+
139
+ /**
140
+ * @returns {Vec3 | null} The current position of the iterator OR null if exceeded maxDistance.
141
+ */
142
+ next(): Vec3 | null;
143
+ }
144
+
145
+ export declare const ManathanIterator: ManhattanIterator;
@@ -0,0 +1,215 @@
1
+ import type { EventEmitter } from "events";
2
+ import type { Vec3 } from "vec3";
3
+ import type { Block } from "prismarine-block";
4
+ import loaderOfChunk from "prismarine-chunk";
5
+ import type { RaycastBlock } from "./iterators";
6
+
7
+ export type Chunk = InstanceType<ReturnType<typeof loaderOfChunk>>;
8
+
9
+ export type ChunkGenerator = (chunkX: number, chunkZ: number) => Chunk;
10
+ export type ChunkCoordinates = { chunkX: number, chunkZ: number };
11
+ export type ChunkCoordsAndColumn = { chunkX: number, chunkZ: number, column: Chunk };
12
+
13
+ export interface StorageProvider {
14
+ load(chunkX: number, chunkZ: number): Promise<Chunk>;
15
+ save(chunkX: number, chunkZ: number, chunk: Chunk): Promise<void>;
16
+ }
17
+
18
+ export declare class World extends EventEmitter {
19
+
20
+ private readonly savingQueue: Map<String, ChunkCoordinates>;
21
+ private finishedSaving: Promise<unknown>;
22
+ private readonly columns: { [key: string]: Chunk };
23
+ public readonly chunkGenerator: ChunkGenerator | null | undefined;
24
+ public readonly storageProvider: StorageProvider | null | undefined;
25
+ public readonly savingInterval: number;
26
+ public readonly sync: WorldSync;
27
+
28
+ /**
29
+ * @param {ChunkGenerator} chunkGenerator A generator that requires X and Z coordinates of lower left of chunk. Returns a {Chunk} chunk object.
30
+ * @param {StorageProvider} storageProvider The provider the world uses to save chunks. See "prismarine-provider-anvil" or "prismarine-provider-raw".
31
+ * @param {number} savingInterval The duration in milliseconds between saves.
32
+ */
33
+ constructor(
34
+ chunkGenerator?: ChunkGenerator | null | undefined,
35
+ storageProvider?: StorageProvider | null | undefined,
36
+ savingInterval?: number,
37
+ );
38
+
39
+ public initialize(
40
+ iniFunc: (x: number, y: number, z: number) => Block,
41
+ length: number,
42
+ width: number,
43
+ height?: number,
44
+ iniPos?: Vec3,
45
+ ): Promise<ChunkCoordinates[]>;
46
+
47
+ /**
48
+ *
49
+ * @param {Vec3} from Position to start raycasting from.
50
+ * @param {Vec3} direction Normalized vector, direction of raycast.
51
+ * @param {number} range Maximum range to raycast.
52
+ * @param {(block: Block) => boolean} matcher Optional function with a block parameter, return true if the raycast should stop at this block, false otherwise.
53
+ */
54
+ public raycast(
55
+ from: Vec3,
56
+ direction: Vec3,
57
+ range: number,
58
+ matcher?: (block: Block) => boolean,
59
+ ): Promise<RaycastBlock | null>;
60
+
61
+ public getLoadedColumn(chunkX: number, chunkZ: number): Chunk;
62
+
63
+ public getColumn(chunkX: number, chunkZ: number): Promise<Chunk>;
64
+
65
+ private _emitBlockUpdate(
66
+ oldBlock: Block,
67
+ newBlock: Block,
68
+ position: Vec3,
69
+ ): void;
70
+
71
+ public setLoadedColumn(
72
+ chunkX: number,
73
+ chunkZ: number,
74
+ chunk: Chunk,
75
+ save?: boolean,
76
+ ): void;
77
+
78
+ public setColumn(
79
+ chunkX: number,
80
+ chunkZ: number,
81
+ chunk: Chunk,
82
+ save?: boolean,
83
+ ): Promise<void>;
84
+
85
+ public unloadColumn(chunkX: number, chunkZ: number): void;
86
+
87
+ public saveNow(): Promise<void>;
88
+
89
+ public startSaving(): void;
90
+
91
+ public waitSaving(): Promise<void>;
92
+
93
+ public stopSaving(): void;
94
+
95
+ public queueSaving(chunkX: number, chunkZ: number): void;
96
+
97
+ public saveAt(pos: Vec3): void;
98
+
99
+ public getColumns(): ChunkCoordsAndColumn[];
100
+
101
+ public getLoadedColumnAt(pos: Vec3): Chunk;
102
+
103
+ public getColumnAt(pos: Vec3): Promise<Chunk>;
104
+
105
+ public setBlock(pos: Vec3, block: Block): Promise<void>;
106
+
107
+ public getBlock(pos: Vec3): Promise<Block>;
108
+
109
+ public getBlockStateId(pos: Vec3): Promise<number>;
110
+
111
+ public getBlockType(pos: Vec3): Promise<number>;
112
+
113
+ public getBlockData(pos: Vec3): Promise<number>;
114
+
115
+ public getBlockLight(pos: Vec3): Promise<number>;
116
+
117
+ public getSkyLight(pos: Vec3): Promise<number>;
118
+
119
+ public getBiome(pos: Vec3): Promise<number>;
120
+
121
+ public setBlockStateId(pos: Vec3, stateId: number): Promise<void>;
122
+
123
+ public setBlockType(pos: Vec3, blockType: number): Promise<void>;
124
+
125
+ public setBlockData(pos: Vec3, data: number): Promise<void>;
126
+
127
+ public setBlockLight(pos: Vec3, light: number): Promise<void>;
128
+
129
+ public setSkyLight(pos: Vec3, light: number): Promise<void>;
130
+
131
+ public setBiome(pos: Vec3, biome: number): Promise<void>;
132
+
133
+ }
134
+
135
+ export declare class WorldSync extends EventEmitter {
136
+
137
+ public readonly async: World;
138
+
139
+ /**
140
+ * @param {World} world Async representation of the World object.
141
+ */
142
+ constructor(world: World);
143
+
144
+
145
+ public initialize(
146
+ iniFunc: (x: number, y: number, z: number) => Block,
147
+ length: number,
148
+ width: number,
149
+ height?: number,
150
+ iniPos?: Vec3,
151
+ ): void;
152
+
153
+ /**
154
+ *
155
+ * @param {Vec3} from Position to start raycasting from.
156
+ * @param {Vec3} direction Normalized vector, direction of raycast.
157
+ * @param {number} range Maximum range to raycast.
158
+ * @param {(block: Block) => boolean} matcher Optional function with a block parameter, return true if the raycast should stop at this block, false otherwise.
159
+ */
160
+ public raycast(
161
+ from: Vec3,
162
+ direction: Vec3,
163
+ range: number,
164
+ matcher?: (block: Block) => boolean,
165
+ ): RaycastBlock | null;
166
+
167
+ private _emitBlockUpdate(
168
+ oldBlock: Block,
169
+ newBlock: Block,
170
+ position: Vec3
171
+ ): void;
172
+
173
+ public getColumns(): ChunkCoordsAndColumn[];
174
+
175
+ public getColumn(chunkX: number, chunkZ: number): Chunk;
176
+
177
+ public getColumnAt(pos: Vec3): Chunk;
178
+
179
+ public setColumn(
180
+ chunkX: number,
181
+ chunkZ: number,
182
+ chunk: Chunk,
183
+ save?: boolean,
184
+ ): void;
185
+
186
+ public unloadColumn(chunkX: number, chunkZ: number): void;
187
+
188
+ public getBlock(pos: Vec3): Block;
189
+
190
+ public getBlockStateId(pos: Vec3): number;
191
+
192
+ public getBlockType(pos: Vec3): number;
193
+
194
+ public getBlockData(pos: Vec3): number;
195
+
196
+ public getBlockLight(pos: Vec3): number;
197
+
198
+ public getSkyLight(pos: Vec3): number;
199
+
200
+ public getBiome(pos: Vec3): number;
201
+
202
+ public setBlock(pos: Vec3, block: Block): void;
203
+
204
+ public setBlockStateId(pos: Vec3, stateId: number): void;
205
+
206
+ public setBlockType(pos: Vec3, blockType: number): void;
207
+
208
+ public setBlockData(pos: Vec3, data: number): void;
209
+
210
+ public setBlockLight(pos: Vec3, light: number): void;
211
+
212
+ public setSkyLight(pos: Vec3, light: number): void;
213
+
214
+ public setBiome(pos: Vec3, biome: number): void;
215
+ }