Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sisilicon
GitHub Repository: sisilicon/worldedit-be
Path: blob/master/src/library/utils/bounds.ts
1784 views
1
import { Dimension, Vector3 } from "@minecraft/server";
2
import { Matrix, Vector } from "@notbeer-api";
3
4
/**
5
* Gives the volume of a space defined by two corners.
6
* @param start The first location
7
* @param end The second location
8
* @return The volume of the space between start and end
9
*/
10
export function regionVolume(start: Vector3, end: Vector3) {
11
const size = regionSize(start, end);
12
return size.x * size.y * size.z;
13
}
14
15
/**
16
* Calculates the minimum and maximum of a set of block locations
17
* @param blocks The set of blocks
18
* @return The minimum and maximum
19
*/
20
export function regionBounds(blocks: Iterable<Vector3>): [Vector, Vector] {
21
let min: Vector;
22
let max: Vector;
23
for (const block of blocks) {
24
if (!min) {
25
min = new Vector(block.x, block.y, block.z);
26
max = new Vector(block.x, block.y, block.z);
27
}
28
min.x = Math.min(block.x, min.x);
29
min.y = Math.min(block.y, min.y);
30
min.z = Math.min(block.z, min.z);
31
max.x = Math.max(block.x, max.x);
32
max.y = Math.max(block.y, max.y);
33
max.z = Math.max(block.z, max.z);
34
}
35
return [min, max];
36
}
37
38
export function regionTransformedBounds(start: Vector3, end: Vector3, transform: Matrix) {
39
start = Vector.add(start, [0, 0, 0]);
40
end = Vector.add(end, [1, 1, 1]);
41
const corners = [
42
new Vector(start.x, start.y, start.z),
43
new Vector(start.x, start.y, end.z),
44
new Vector(start.x, end.y, start.z),
45
new Vector(start.x, end.y, end.z),
46
new Vector(end.x, start.y, start.z),
47
new Vector(end.x, start.y, end.z),
48
new Vector(end.x, end.y, start.z),
49
new Vector(end.x, end.y, end.z),
50
].map((vec) => vec.transform(transform));
51
52
let [min, max] = [Vector.INF, Vector.NEG_INF];
53
corners.forEach((vec) => (min = min.min(vec)));
54
corners.forEach((vec) => (max = max.max(vec)));
55
56
return [min.floor(), max.sub(1).ceil()] as [Vector, Vector];
57
}
58
59
export function regionOffset(start: Vector3, end: Vector3, offset: Vector3): [Vector, Vector] {
60
return [Vector.add(start, offset), Vector.add(end, offset)];
61
}
62
63
/**
64
* Gives the center of a space defined by two corners.
65
* @param start The first location
66
* @param end The second location
67
* @return The center of the space between start and end
68
*/
69
export function regionCenter(start: Vector3, end: Vector3): Vector {
70
return new Vector(Math.floor(start.x + (end.x - start.x) * 0.5), Math.floor(start.y + (end.y - start.y) * 0.5), Math.floor(start.z + (end.z - start.z) * 0.5));
71
}
72
73
/**
74
* Gets the size of a region across its three axis.
75
* @param start The first corner of the region
76
* @param end The second corner of the region
77
* @return The size of the region
78
*/
79
export function regionSize(start: Vector3, end: Vector3) {
80
return new Vector(Math.abs(start.x - end.x) + 1, Math.abs(start.y - end.y) + 1, Math.abs(start.z - end.z) + 1);
81
}
82
83
/**
84
* Generates blocks that exist between `start` and `end`
85
* @param start
86
* @param end
87
*/
88
export function* regionIterateBlocks(start: Vector3, end: Vector3, centered = false) {
89
let [min, max] = regionBounds([start, end]).map((block) => Vector.from(block));
90
if (centered) {
91
min = min.add(0.5);
92
max = max.add(0.5);
93
}
94
for (let z = min.z; z <= max.z; z++) {
95
for (let y = min.y; y <= max.y; y++) {
96
for (let x = min.x; x <= max.x; x++) {
97
yield { x, y, z } as Vector3;
98
}
99
}
100
}
101
}
102
103
/**
104
* Generates chunks that exist between `start` and `end`
105
* @param start
106
* @param end
107
*/
108
export function* regionIterateChunks(start: Vector3, end: Vector3, ySubChunks = true) {
109
const [min, max] = regionBounds([start, end]).map((block) => Vector.from(block));
110
const minChunk = min
111
.mul(1 / 16)
112
.floor()
113
.mul(16);
114
const maxChunk = max
115
.mul(1 / 16)
116
.floor()
117
.mul(16)
118
.add(16);
119
for (let chunkZ = minChunk.z; chunkZ < maxChunk.z; chunkZ += 16) {
120
for (let chunkX = minChunk.x; chunkX < maxChunk.x; chunkX += 16) {
121
if (ySubChunks) {
122
for (let chunkY = minChunk.y; chunkY < maxChunk.y; chunkY += 16) {
123
const chunk = new Vector(chunkX, chunkY, chunkZ);
124
yield [min.max(chunk), max.min(chunk.add(15))] as [Vector, Vector];
125
}
126
} else {
127
const chunk = new Vector(chunkX, minChunk.y, chunkZ);
128
yield [min.max(chunk), max.min(chunk.add(15))] as [Vector, Vector];
129
}
130
}
131
}
132
}
133
134
export function regionLoaded(start: Vector3, end: Vector3, dimension: Dimension) {
135
for (const chunk of regionIterateChunks(start, end, false)) {
136
if (!dimension.getBlock(chunk[0])) return false;
137
}
138
return true;
139
}
140
141