SHOW:
|
|
- or go back to the newest paste.
1 | package me.trow.Teste; | |
2 | ||
3 | import java.util.ArrayList; | |
4 | import java.util.HashMap; | |
5 | import java.util.Iterator; | |
6 | import java.util.List; | |
7 | import java.util.Map; | |
8 | import org.bukkit.Bukkit; | |
9 | import org.bukkit.Chunk; | |
10 | import org.bukkit.Location; | |
11 | import org.bukkit.World; | |
12 | import org.bukkit.block.Block; | |
13 | import org.bukkit.configuration.serialization.ConfigurationSerializable; | |
14 | ||
15 | public class CuboID implements Iterable<Block>, Cloneable, ConfigurationSerializable{ | |
16 | protected final String worldName; | |
17 | protected final int x1; | |
18 | protected final int y1; | |
19 | protected final int z1; | |
20 | protected final int x2; | |
21 | protected final int y2; | |
22 | protected final int z2; | |
23 | ||
24 | public CuboID(Location l1, Location l2){ | |
25 | if (!l1.getWorld().equals(l2.getWorld())) { | |
26 | throw new IllegalArgumentException("Locations must be on the same world"); | |
27 | } | |
28 | this.worldName = l1.getWorld().getName(); | |
29 | this.x1 = Math.min(l1.getBlockX(), l2.getBlockX()); | |
30 | this.y1 = Math.min(l1.getBlockY(), l2.getBlockY()); | |
31 | this.z1 = Math.min(l1.getBlockZ(), l2.getBlockZ()); | |
32 | this.x2 = Math.max(l1.getBlockX(), l2.getBlockX()); | |
33 | this.y2 = Math.max(l1.getBlockY(), l2.getBlockY()); | |
34 | this.z2 = Math.max(l1.getBlockZ(), l2.getBlockZ()); | |
35 | } | |
36 | ||
37 | public CuboID(Location l1){ | |
38 | this(l1, l1); | |
39 | } | |
40 | ||
41 | public CuboID(CuboID other){ | |
42 | this(other.getWorld().getName(), other.x1, other.y1, other.z1, other.x2, other.y2, other.z2); | |
43 | } | |
44 | ||
45 | public CuboID(World world, int x1, int y1, int z1, int x2, int y2, int z2){ | |
46 | this.worldName = world.getName(); | |
47 | this.x1 = Math.min(x1, x2); | |
48 | this.x2 = Math.max(x1, x2); | |
49 | this.y1 = Math.min(y1, y2); | |
50 | this.y2 = Math.max(y1, y2); | |
51 | this.z1 = Math.min(z1, z2); | |
52 | this.z2 = Math.max(z1, z2); | |
53 | } | |
54 | ||
55 | private CuboID(String worldName, int x1, int y1, int z1, int x2, int y2, int z2){ | |
56 | this.worldName = worldName; | |
57 | this.x1 = Math.min(x1, x2); | |
58 | this.x2 = Math.max(x1, x2); | |
59 | this.y1 = Math.min(y1, y2); | |
60 | this.y2 = Math.max(y1, y2); | |
61 | this.z1 = Math.min(z1, z2); | |
62 | this.z2 = Math.max(z1, z2); | |
63 | } | |
64 | ||
65 | public CuboID(Map<String, Object> map){ | |
66 | this.worldName = ((String)map.get("worldName")); | |
67 | this.x1 = ((Integer)map.get("x1")).intValue(); | |
68 | this.x2 = ((Integer)map.get("x2")).intValue(); | |
69 | this.y1 = ((Integer)map.get("y1")).intValue(); | |
70 | this.y2 = ((Integer)map.get("y2")).intValue(); | |
71 | this.z1 = ((Integer)map.get("z1")).intValue(); | |
72 | this.z2 = ((Integer)map.get("z2")).intValue(); | |
73 | } | |
74 | ||
75 | public Map<String, Object> serialize(){ | |
76 | Map<String, Object> map = new HashMap(); | |
77 | map.put("worldName", this.worldName); | |
78 | map.put("x1", Integer.valueOf(this.x1)); | |
79 | map.put("y1", Integer.valueOf(this.y1)); | |
80 | map.put("z1", Integer.valueOf(this.z1)); | |
81 | map.put("x2", Integer.valueOf(this.x2)); | |
82 | map.put("y2", Integer.valueOf(this.y2)); | |
83 | map.put("z2", Integer.valueOf(this.z2)); | |
84 | return map; | |
85 | } | |
86 | ||
87 | public Location getLowerNE(){ | |
88 | return new Location(getWorld(), this.x1, this.y1, this.z1); | |
89 | } | |
90 | ||
91 | public Location getUpperSW(){ | |
92 | return new Location(getWorld(), this.x2, this.y2, this.z2); | |
93 | } | |
94 | ||
95 | public List<Block> getBlocks(){ | |
96 | Iterator<Block> blockI = iterator(); | |
97 | List<Block> copy = new ArrayList(); | |
98 | while (blockI.hasNext()) { | |
99 | copy.add((Block)blockI.next()); | |
100 | } | |
101 | return copy; | |
102 | } | |
103 | ||
104 | public Location getCenter(){ | |
105 | int x1 = getUpperX() + 1; | |
106 | int y1 = getUpperY() + 1; | |
107 | int z1 = getUpperZ() + 1; | |
108 | return new Location(getWorld(), getLowerX() + (x1 - getLowerX()) / 2.0D, getLowerY() + (y1 - getLowerY()) / 2.0D, getLowerZ() + (z1 - getLowerZ()) / 2.0D); | |
109 | } | |
110 | ||
111 | public World getWorld() | |
112 | { | |
113 | World world = Bukkit.getWorld(this.worldName); | |
114 | if (world == null) { | |
115 | throw new IllegalStateException("World '" + this.worldName + "' is not loaded"); | |
116 | } | |
117 | return world; | |
118 | } | |
119 | ||
120 | public int getSizeX(){ | |
121 | return this.x2 - this.x1 + 1; | |
122 | } | |
123 | ||
124 | public int getSizeY(){ | |
125 | return this.y2 - this.y1 + 1; | |
126 | } | |
127 | ||
128 | public int getSizeZ(){ | |
129 | return this.z2 - this.z1 + 1; | |
130 | } | |
131 | ||
132 | public int getLowerX(){ | |
133 | return this.x1; | |
134 | } | |
135 | ||
136 | public int getLowerY(){ | |
137 | return this.y1; | |
138 | } | |
139 | ||
140 | public int getLowerZ(){ | |
141 | return this.z1; | |
142 | } | |
143 | ||
144 | public int getUpperX(){ | |
145 | return this.x2; | |
146 | } | |
147 | ||
148 | public int getUpperY(){ | |
149 | return this.y2; | |
150 | } | |
151 | ||
152 | public int getUpperZ(){ | |
153 | return this.z2; | |
154 | } | |
155 | ||
156 | public Block[] corners(){ | |
157 | Block[] res = new Block[8]; | |
158 | World w = getWorld(); | |
159 | res[0] = w.getBlockAt(this.x1, this.y1, this.z1); | |
160 | res[1] = w.getBlockAt(this.x1, this.y1, this.z2); | |
161 | res[2] = w.getBlockAt(this.x1, this.y2, this.z1); | |
162 | res[3] = w.getBlockAt(this.x1, this.y2, this.z2); | |
163 | res[4] = w.getBlockAt(this.x2, this.y1, this.z1); | |
164 | res[5] = w.getBlockAt(this.x2, this.y1, this.z2); | |
165 | res[6] = w.getBlockAt(this.x2, this.y2, this.z1); | |
166 | res[7] = w.getBlockAt(this.x2, this.y2, this.z2); | |
167 | return res; | |
168 | } | |
169 | ||
170 | public CuboID expand(CuboidDirection dir, int amount){ | |
171 | switch (dir){ | |
172 | case Both: | |
173 | return new CuboID(this.worldName, this.x1 - amount, this.y1, this.z1, this.x2, this.y2, this.z2); | |
174 | case East: | |
175 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2 + amount, this.y2, this.z2); | |
176 | case Down: | |
177 | return new CuboID(this.worldName, this.x1, this.y1, this.z1 - amount, this.x2, this.y2, this.z2); | |
178 | case Horizontal: | |
179 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z2 + amount); | |
180 | case South: | |
181 | return new CuboID(this.worldName, this.x1, this.y1 - amount, this.z1, this.x2, this.y2, this.z2); | |
182 | case North: | |
183 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2 + amount, this.z2); | |
184 | } | |
185 | throw new IllegalArgumentException("Invalid direction " + dir); | |
186 | } | |
187 | ||
188 | public CuboID shift(CuboidDirection dir, int amount){ | |
189 | return expand(dir, amount).expand(dir.opposite(), -amount); | |
190 | } | |
191 | ||
192 | public CuboID outset(CuboidDirection dir, int amount){ | |
193 | CuboID c; | |
194 | CuboID c1; | |
195 | CuboID c2; | |
196 | switch (dir){ | |
197 | case Unknown: | |
198 | c = expand(CuboidDirection.North, amount).expand(CuboidDirection.South, amount).expand(CuboidDirection.East, amount).expand(CuboidDirection.West, amount); | |
199 | break; | |
200 | case Up: | |
201 | c = expand(CuboidDirection.Down, amount).expand(CuboidDirection.Up, amount); | |
202 | break; | |
203 | case Vertical: | |
204 | c = outset(CuboidDirection.Horizontal, amount).outset(CuboidDirection.Vertical, amount); | |
205 | break; | |
206 | default: | |
207 | throw new IllegalArgumentException("Invalid direction " + dir); | |
208 | } | |
209 | CuboID c3; | |
210 | return c; | |
211 | } | |
212 | ||
213 | public CuboID inset(CuboidDirection dir, int amount){ | |
214 | return outset(dir, -amount); | |
215 | } | |
216 | ||
217 | public boolean contains(int x, int y, int z){ | |
218 | return (x >= this.x1) && (x <= this.x2) && (y >= this.y1) && (y <= this.y2) && (z >= this.z1) && (z <= this.z2); | |
219 | } | |
220 | ||
221 | public boolean contains(Block b){ | |
222 | return contains(b.getLocation()); | |
223 | } | |
224 | ||
225 | public boolean contains(Location l){ | |
226 | if (!this.worldName.equals(l.getWorld().getName())) { | |
227 | return false; | |
228 | } | |
229 | return contains(l.getBlockX(), l.getBlockY(), l.getBlockZ()); | |
230 | } | |
231 | ||
232 | public int getVolume(){ | |
233 | return getSizeX() * getSizeY() * getSizeZ(); | |
234 | } | |
235 | ||
236 | public byte getAverageLightLevel(){ | |
237 | long total = 0L; | |
238 | int n = 0; | |
239 | for (Block b : this) { | |
240 | if (b.isEmpty()){ | |
241 | total += b.getLightLevel(); | |
242 | n++; | |
243 | } | |
244 | } | |
245 | return n > 0 ? (byte)(int)(total / n) : 0; | |
246 | } | |
247 | ||
248 | public CuboID contract(){ | |
249 | return contract(CuboidDirection.Down).contract(CuboidDirection.South).contract(CuboidDirection.East).contract(CuboidDirection.Up).contract(CuboidDirection.North).contract(CuboidDirection.West); | |
250 | } | |
251 | ||
252 | public CuboID contract(CuboidDirection dir){ | |
253 | CuboID face = getFace(dir.opposite()); | |
254 | switch (dir){ | |
255 | case South: | |
256 | while ((face.containsOnly(0)) && (face.getLowerY() > getLowerY())) { | |
257 | face = face.shift(CuboidDirection.Down, 1); | |
258 | } | |
259 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2, face.getUpperY(), this.z2); | |
260 | case North: | |
261 | while ((face.containsOnly(0)) && (face.getUpperY() < getUpperY())) { | |
262 | face = face.shift(CuboidDirection.Up, 1); | |
263 | } | |
264 | return new CuboID(this.worldName, this.x1, face.getLowerY(), this.z1, this.x2, this.y2, this.z2); | |
265 | case Both: | |
266 | while ((face.containsOnly(0)) && (face.getLowerX() > getLowerX())) { | |
267 | face = face.shift(CuboidDirection.North, 1); | |
268 | } | |
269 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, face.getUpperX(), this.y2, this.z2); | |
270 | case East: | |
271 | while ((face.containsOnly(0)) && (face.getUpperX() < getUpperX())) { | |
272 | face = face.shift(CuboidDirection.South, 1); | |
273 | } | |
274 | return new CuboID(this.worldName, face.getLowerX(), this.y1, this.z1, this.x2, this.y2, this.z2); | |
275 | case Down: | |
276 | while ((face.containsOnly(0)) && (face.getLowerZ() > getLowerZ())) { | |
277 | face = face.shift(CuboidDirection.East, 1); | |
278 | } | |
279 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, face.getUpperZ()); | |
280 | case Horizontal: | |
281 | while ((face.containsOnly(0)) && (face.getUpperZ() < getUpperZ())) { | |
282 | face = face.shift(CuboidDirection.West, 1); | |
283 | } | |
284 | return new CuboID(this.worldName, this.x1, this.y1, face.getLowerZ(), this.x2, this.y2, this.z2); | |
285 | } | |
286 | throw new IllegalArgumentException("Invalid direction " + dir); | |
287 | } | |
288 | ||
289 | public CuboID getFace(CuboidDirection dir){ | |
290 | switch (dir){ | |
291 | case South: | |
292 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y1, this.z2); | |
293 | case North: | |
294 | return new CuboID(this.worldName, this.x1, this.y2, this.z1, this.x2, this.y2, this.z2); | |
295 | case Both: | |
296 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x1, this.y2, this.z2); | |
297 | case East: | |
298 | return new CuboID(this.worldName, this.x2, this.y1, this.z1, this.x2, this.y2, this.z2); | |
299 | case Down: | |
300 | return new CuboID(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z1); | |
301 | case Horizontal: | |
302 | return new CuboID(this.worldName, this.x1, this.y1, this.z2, this.x2, this.y2, this.z2); | |
303 | } | |
304 | throw new IllegalArgumentException("Invalid direction " + dir); | |
305 | } | |
306 | ||
307 | public boolean containsOnly(int blockId){ | |
308 | for (Block b : this) { | |
309 | if (b.getTypeId() != blockId) { | |
310 | return false; | |
311 | } | |
312 | } | |
313 | return true; | |
314 | } | |
315 | ||
316 | public CuboID getBoundingCuboid(CuboID other){ | |
317 | if (other == null) { | |
318 | return this; | |
319 | } | |
320 | int xMin = Math.min(getLowerX(), other.getLowerX()); | |
321 | int yMin = Math.min(getLowerY(), other.getLowerY()); | |
322 | int zMin = Math.min(getLowerZ(), other.getLowerZ()); | |
323 | int xMax = Math.max(getUpperX(), other.getUpperX()); | |
324 | int yMax = Math.max(getUpperY(), other.getUpperY()); | |
325 | int zMax = Math.max(getUpperZ(), other.getUpperZ()); | |
326 | ||
327 | return new CuboID(this.worldName, xMin, yMin, zMin, xMax, yMax, zMax); | |
328 | } | |
329 | ||
330 | public Block getRelativeBlock(int x, int y, int z){ | |
331 | return getWorld().getBlockAt(this.x1 + x, this.y1 + y, this.z1 + z); | |
332 | } | |
333 | ||
334 | public Block getRelativeBlock(World w, int x, int y, int z){ | |
335 | return w.getBlockAt(this.x1 + x, this.y1 + y, this.z1 + z); | |
336 | } | |
337 | ||
338 | public List<Chunk> getChunks(){ | |
339 | List<Chunk> res = new ArrayList(); | |
340 | ||
341 | World w = getWorld(); | |
342 | int x1 = getLowerX() & 0xFFFFFFF0; | |
343 | int x2 = getUpperX() & 0xFFFFFFF0; | |
344 | int z1 = getLowerZ() & 0xFFFFFFF0; | |
345 | int z2 = getUpperZ() & 0xFFFFFFF0; | |
346 | for (int x = x1; x <= x2; x += 16) { | |
347 | for (int z = z1; z <= z2; z += 16) { | |
348 | res.add(w.getChunkAt(x >> 4, z >> 4)); | |
349 | } | |
350 | } | |
351 | return res; | |
352 | } | |
353 | ||
354 | public Iterator<Block> iterator(){ | |
355 | return new CuboidIterator(getWorld(), this.x1, this.y1, this.z1, this.x2, this.y2, this.z2); | |
356 | } | |
357 | ||
358 | public CuboID clone(){ | |
359 | return new CuboID(this); | |
360 | } | |
361 | ||
362 | public String toString(){ | |
363 | return new String("Cuboid: " + this.worldName + "," + this.x1 + "," + this.y1 + "," + this.z1 + "=>" + this.x2 + "," + this.y2 + "," + this.z2); | |
364 | } | |
365 | ||
366 | public class CuboidIterator implements Iterator<Block>{ | |
367 | private World w; | |
368 | private int baseX; | |
369 | private int baseY; | |
370 | private int baseZ; | |
371 | private int x; | |
372 | private int y; | |
373 | private int z; | |
374 | private int sizeX; | |
375 | private int sizeY; | |
376 | private int sizeZ; | |
377 | ||
378 | public CuboidIterator(World w, int x1, int y1, int z1, int x2, int y2, int z2){ | |
379 | this.w = w; | |
380 | this.baseX = x1; | |
381 | this.baseY = y1; | |
382 | this.baseZ = z1; | |
383 | this.sizeX = (Math.abs(x2 - x1) + 1); | |
384 | this.sizeY = (Math.abs(y2 - y1) + 1); | |
385 | this.sizeZ = (Math.abs(z2 - z1) + 1); | |
386 | this.x = (this.y = this.z = 0); | |
387 | } | |
388 | ||
389 | public boolean hasNext(){ | |
390 | return (this.x < this.sizeX) && (this.y < this.sizeY) && (this.z < this.sizeZ); | |
391 | } | |
392 | ||
393 | public Block next(){ | |
394 | Block b = this.w.getBlockAt(this.baseX + this.x, this.baseY + this.y, this.baseZ + this.z); | |
395 | if (++this.x >= this.sizeX){ | |
396 | this.x = 0; | |
397 | if (++this.y >= this.sizeY){ | |
398 | this.y = 0; | |
399 | this.z += 1; | |
400 | } | |
401 | } | |
402 | return b; | |
403 | } | |
404 | ||
405 | public void remove() {} | |
406 | } | |
407 | ||
408 | public static enum CuboidDirection{ | |
409 | North, East, South, West, Up, Down, Horizontal, Vertical, Both, Unknown; | |
410 | ||
411 | public CuboidDirection opposite(){ | |
412 | switch (this){ | |
413 | case Both: | |
414 | return South; | |
415 | case Down: | |
416 | return West; | |
417 | case East: | |
418 | return North; | |
419 | case Horizontal: | |
420 | return East; | |
421 | case Unknown: | |
422 | return Vertical; | |
423 | case Up: | |
424 | return Horizontal; | |
425 | case North: | |
426 | return Down; | |
427 | case South: | |
428 | return Up; | |
429 | case Vertical: | |
430 | return Both; | |
431 | } | |
432 | return Unknown; | |
433 | } | |
434 | } | |
435 | } |