Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package net.minecraft.server;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.Iterator;
8import java.util.List;
9import java.util.Map;
10import java.util.Random;
11import java.util.Set;
12import java.util.TreeSet;
13import java.util.UUID;
14
15import org.bukkit.Bukkit;
16import org.bukkit.Location;
17import org.bukkit.block.BlockState;
18import org.bukkit.craftbukkit.CraftServer;
19import org.bukkit.craftbukkit.CraftWorld;
20import org.bukkit.craftbukkit.event.CraftEventFactory;
21import org.bukkit.event.block.BlockBreakEvent;
22import org.bukkit.event.block.BlockCanBuildEvent;
23import org.bukkit.event.block.BlockFormEvent;
24import org.bukkit.event.block.BlockPhysicsEvent;
25import org.bukkit.event.entity.CreatureSpawnEvent;
26import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
27import org.bukkit.event.entity.EntityDamageEvent;
28import org.bukkit.event.entity.ItemSpawnEvent;
29import org.bukkit.event.weather.ThunderChangeEvent;
30import org.bukkit.event.weather.WeatherChangeEvent;
31import org.bukkit.generator.ChunkGenerator;
32
33import uk.betacraft.uberbukkit.Uberbukkit;
34import uk.betacraft.uberbukkit.UberbukkitConfig;
35
36// CraftBukkit start
37// CraftBukkit end
38
39public class World implements IBlockAccess {
40
41 // uberbukkit
42 private static final boolean pre1_5_placement_rules = UberbukkitConfig.getInstance().getBoolean("mechanics.pre_b1_5_block_placement_rules", false);
43
44 public boolean a = false;
45 private List C = new ArrayList();
46 public List entityList = new ArrayList();
47 private List D = new ArrayList();
48 private TreeSet E = new TreeSet();
49 private Set F = new HashSet();
50 public List c = new ArrayList();
51 private List G = new ArrayList();
52 public List players = new ArrayList();
53 public List e = new ArrayList();
54 private long H = 16777215L;
55 public int f = 0;
56 protected int g = (new Random()).nextInt();
57 protected final int h = 1013904223;
58 protected float i;
59 protected float j;
60 protected float k;
61 protected float l;
62 protected int m = 0;
63 public int n = 0;
64 public boolean suppressPhysics = false;
65 private long I = System.currentTimeMillis();
66 protected int p = 40;
67 public int spawnMonsters;
68 public Random random = new Random();
69 public boolean s = false;
70 public WorldProvider worldProvider; // CraftBukkit - remove final
71 protected List u = new ArrayList();
72 public IChunkProvider chunkProvider; // CraftBukkit - protected -> public
73 protected final IDataManager w;
74 public WorldData worldData; // CraftBukkit - protected -> public
75 public boolean isLoading;
76 private boolean J;
77 public WorldMapCollection worldMaps;
78 private ArrayList K = new ArrayList();
79 private boolean L;
80 private int M = 0;
81 public boolean allowMonsters = true; // CraftBukkit - private -> public
82 public boolean allowAnimals = true; // CraftBukkit - private -> public
83 static int A = 0;
84 private Set P = new HashSet();
85 private int Q;
86 private List R;
87 public boolean isStatic;
88 public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
89
90 public WorldChunkManager getWorldChunkManager() {
91 return this.worldProvider.b;
92 }
93
94 // CraftBukkit start
95 private final CraftWorld world;
96 public boolean pvpMode;
97 public boolean keepSpawnInMemory = true;
98 public ChunkGenerator generator;
99 Chunk lastChunkAccessed;
100 int lastXAccessed = Integer.MIN_VALUE;
101 int lastZAccessed = Integer.MIN_VALUE;
102 final Object chunkLock = new Object();
103 private List<TileEntity> tileEntitiesToUnload;
104
105 private boolean canSpawn(int x, int z) {
106 if (this.generator != null) {
107 return this.generator.canSpawn(this.getWorld(), x, z);
108 } else {
109 return this.worldProvider.canSpawn(x, z);
110 }
111 }
112
113 public CraftWorld getWorld() {
114 return this.world;
115 }
116
117 public CraftServer getServer() {
118 return (CraftServer) Bukkit.getServer();
119 }
120
121 public void markForRemoval(TileEntity tileentity) {
122 tileEntitiesToUnload.add(tileentity);
123 }
124
125 // CraftBukkit - changed signature
126 public World(IDataManager idatamanager, String s, long i, WorldProvider worldprovider, ChunkGenerator gen, org.bukkit.World.Environment env) {
127 this.generator = gen;
128 this.world = new CraftWorld((WorldServer) this, gen, env);
129 tileEntitiesToUnload = new ArrayList<TileEntity>();
130 // CraftBukkit end
131
132 this.Q = this.random.nextInt(12000);
133 this.R = new ArrayList();
134 this.isStatic = false;
135 this.w = idatamanager;
136 this.worldMaps = new WorldMapCollection(idatamanager);
137 this.worldData = idatamanager.c();
138 this.s = this.worldData == null;
139 if (worldprovider != null) {
140 this.worldProvider = worldprovider;
141 } else if (this.worldData != null && this.worldData.h() == -1) {
142 this.worldProvider = WorldProvider.byDimension(-1);
143 } else {
144 this.worldProvider = WorldProvider.byDimension(0);
145 }
146
147 boolean flag = false;
148
149 if (this.worldData == null) {
150 this.worldData = new WorldData(i, s);
151 flag = true;
152 } else {
153 this.worldData.a(s);
154 }
155
156 this.worldProvider.a(this);
157 this.chunkProvider = this.b();
158 if (flag) {
159 this.c();
160 }
161
162 this.g();
163 this.x();
164
165 this.getServer().addWorld(this.world); // CraftBukkit
166 }
167
168 protected IChunkProvider b() {
169 IChunkLoader ichunkloader = this.w.a(this.worldProvider);
170
171 return new ChunkProviderLoadOrGenerate(this, ichunkloader, this.worldProvider.getChunkProvider());
172 }
173
174 protected void c() {
175 this.isLoading = true;
176 int i = 0;
177 byte b0 = 64;
178
179 int j;
180
181 // CraftBukkit start
182 if (this.generator != null) {
183 Random rand = new Random(this.getSeed());
184 Location spawn = this.generator.getFixedSpawnLocation(((WorldServer) this).getWorld(), rand);
185
186 if (spawn != null) {
187 if (spawn.getWorld() != ((WorldServer) this).getWorld()) {
188 throw new IllegalStateException("Cannot set spawn point for " + this.worldData.name + " to be in another world (" + spawn.getWorld().getName() + ")");
189 } else {
190 this.worldData.setSpawn(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ());
191 this.isLoading = false;
192 return;
193 }
194 }
195 }
196
197 for (j = 0; !this.canSpawn(i, j); j += this.random.nextInt(64) - this.random.nextInt(64)) {
198 i += this.random.nextInt(64) - this.random.nextInt(64);
199 }
200 // CraftBukkit end
201
202 this.worldData.setSpawn(i, b0, j);
203 this.isLoading = false;
204 }
205
206 public int a(int i, int j) {
207 int k;
208
209 for (k = 63; !this.isEmpty(i, k + 1, j); ++k) {
210 ;
211 }
212
213 return this.getTypeId(i, k, j);
214 }
215
216 public void save(boolean flag, IProgressUpdate iprogressupdate) {
217 if (this.chunkProvider.canSave()) {
218 if (iprogressupdate != null) {
219 iprogressupdate.a("Saving level");
220 }
221
222 this.w();
223 if (iprogressupdate != null) {
224 iprogressupdate.b("Saving chunks");
225 }
226
227 this.chunkProvider.saveChunks(flag, iprogressupdate);
228 }
229 }
230
231 private void w() {
232 this.k();
233 this.w.a(this.worldData, this.players);
234 this.worldMaps.a();
235 }
236
237 public int getTypeId(int i, int j, int k) {
238 return i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000 ? (j < 0 ? 0 : (j >= 128 ? 0 : this.getChunkAt(i >> 4, k >> 4).getTypeId(i & 15, j, k & 15))) : 0;
239 }
240
241 public boolean isEmpty(int i, int j, int k) {
242 return this.getTypeId(i, j, k) == 0;
243 }
244
245 public boolean isLoaded(int i, int j, int k) {
246 return j >= 0 && j < 128 ? this.isChunkLoaded(i >> 4, k >> 4) : false;
247 }
248
249 public boolean areChunksLoaded(int i, int j, int k, int l) {
250 return this.a(i - l, j - l, k - l, i + l, j + l, k + l);
251 }
252
253 public boolean a(int i, int j, int k, int l, int i1, int j1) {
254 if (i1 >= 0 && j < 128) {
255 i >>= 4;
256 j >>= 4;
257 k >>= 4;
258 l >>= 4;
259 i1 >>= 4;
260 j1 >>= 4;
261
262 for (int k1 = i; k1 <= l; ++k1) {
263 for (int l1 = k; l1 <= j1; ++l1) {
264 if (!this.isChunkLoaded(k1, l1)) {
265 return false;
266 }
267 }
268 }
269
270 return true;
271 } else {
272 return false;
273 }
274 }
275
276 private boolean isChunkLoaded(int i, int j) {
277 return this.chunkProvider.isChunkLoaded(i, j);
278 }
279
280 public Chunk getChunkAtWorldCoords(int i, int j) {
281 return this.getChunkAt(i >> 4, j >> 4);
282 }
283
284 // CraftBukkit start
285 public Chunk getChunkAt(int i, int j) {
286 Chunk result = null;
287 synchronized (this.chunkLock) {
288 if (this.lastChunkAccessed == null || this.lastXAccessed != i || this.lastZAccessed != j) {
289 this.lastXAccessed = i;
290 this.lastZAccessed = j;
291 this.lastChunkAccessed = this.chunkProvider.getOrCreateChunk(i, j);
292 }
293 result = this.lastChunkAccessed;
294 }
295 return result;
296 }
297 // CraftBukkit end
298
299 public boolean setRawTypeIdAndData(int i, int j, int k, int l, int i1) {
300 // uberbukkit
301 if (!Uberbukkit.getProtocolHandler().canReceiveBlockItem(l)) {
302 return false;
303 }
304
305 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
306 if (j < 0) {
307 return false;
308 } else if (j >= 128) {
309 return false;
310 } else {
311 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
312
313 return chunk.a(i & 15, j, k & 15, l, i1);
314 }
315 } else {
316 return false;
317 }
318 }
319
320 public boolean setRawTypeId(int i, int j, int k, int l) {
321 // uberbukkit
322 if (!Uberbukkit.getProtocolHandler().canReceiveBlockItem(l)) {
323 return false;
324 }
325
326 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
327 if (j < 0) {
328 return false;
329 } else if (j >= 128) {
330 return false;
331 } else {
332 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
333
334 return chunk.a(i & 15, j, k & 15, l);
335 }
336 } else {
337 return false;
338 }
339 }
340
341 public Material getMaterial(int i, int j, int k) {
342 int l = this.getTypeId(i, j, k);
343
344 return l == 0 ? Material.AIR : Block.byId[l].material;
345 }
346
347 public int getData(int i, int j, int k) {
348 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
349 if (j < 0) {
350 return 0;
351 } else if (j >= 128) {
352 return 0;
353 } else {
354 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
355
356 i &= 15;
357 k &= 15;
358 return chunk.getData(i, j, k);
359 }
360 } else {
361 return 0;
362 }
363 }
364
365 public void setData(int i, int j, int k, int l) {
366 if (this.setRawData(i, j, k, l)) {
367 int i1 = this.getTypeId(i, j, k);
368
369 if (Block.t[i1 & 255]) {
370 this.update(i, j, k, i1);
371 } else {
372 this.applyPhysics(i, j, k, i1);
373 }
374 }
375 }
376
377 public boolean setRawData(int i, int j, int k, int l) {
378 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
379 if (j < 0) {
380 return false;
381 } else if (j >= 128) {
382 return false;
383 } else {
384 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
385
386 i &= 15;
387 k &= 15;
388 chunk.b(i, j, k, l);
389 return true;
390 }
391 } else {
392 return false;
393 }
394 }
395
396 public boolean setTypeId(int i, int j, int k, int l) {
397 // CraftBukkit start
398 int old = this.getTypeId(i, j, k);
399 if (this.setRawTypeId(i, j, k, l)) {
400 this.update(i, j, k, l == 0 ? old : l);
401 return true;
402 } else {
403 return false;
404 }
405 // CraftBukkit end
406 }
407
408 public boolean setTypeIdAndData(int i, int j, int k, int l, int i1) {
409 // CraftBukkit start
410 int old = this.getTypeId(i, j, k);
411 if (this.setRawTypeIdAndData(i, j, k, l, i1)) {
412 this.update(i, j, k, l == 0 ? old : l);
413 return true;
414 } else {
415 return false;
416 }
417 // CraftBukkit end
418 }
419
420 public void notify(int i, int j, int k) {
421 for (int l = 0; l < this.u.size(); ++l) {
422 ((IWorldAccess) this.u.get(l)).a(i, j, k);
423 }
424 }
425
426 protected void update(int i, int j, int k, int l) {
427 this.notify(i, j, k);
428 this.applyPhysics(i, j, k, l);
429 }
430
431 public void g(int i, int j, int k, int l) {
432 if (k > l) {
433 int i1 = l;
434
435 l = k;
436 k = i1;
437 }
438
439 this.b(i, k, j, i, l, j);
440 }
441
442 public void i(int i, int j, int k) {
443 for (int l = 0; l < this.u.size(); ++l) {
444 ((IWorldAccess) this.u.get(l)).a(i, j, k, i, j, k);
445 }
446 }
447
448 public void b(int i, int j, int k, int l, int i1, int j1) {
449 for (int k1 = 0; k1 < this.u.size(); ++k1) {
450 ((IWorldAccess) this.u.get(k1)).a(i, j, k, l, i1, j1);
451 }
452 }
453
454 public void applyPhysics(int i, int j, int k, int l) {
455 this.k(i - 1, j, k, l);
456 this.k(i + 1, j, k, l);
457 this.k(i, j - 1, k, l);
458 this.k(i, j + 1, k, l);
459 this.k(i, j, k - 1, l);
460 this.k(i, j, k + 1, l);
461 }
462
463 private void k(int i, int j, int k, int l) {
464 if (!this.suppressPhysics && !this.isStatic) {
465 Block block = Block.byId[this.getTypeId(i, j, k)];
466
467 if (block != null) {
468 // CraftBukkit start
469 CraftWorld world = ((WorldServer) this).getWorld();
470 if (world != null) {
471 BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(i, j, k), l);
472 this.getServer().getPluginManager().callEvent(event);
473
474 if (event.isCancelled()) {
475 return;
476 }
477 }
478 // CraftBukkit end
479
480 block.doPhysics(this, i, j, k, l);
481 }
482 }
483 }
484
485 public boolean isChunkLoaded(int i, int j, int k) {
486 return this.getChunkAt(i >> 4, k >> 4).c(i & 15, j, k & 15);
487 }
488
489 public int k(int i, int j, int k) {
490 if (j < 0) {
491 return 0;
492 } else {
493 if (j >= 128) {
494 j = 127;
495 }
496
497 return this.getChunkAt(i >> 4, k >> 4).c(i & 15, j, k & 15, 0);
498 }
499 }
500
501 public int getLightLevel(int i, int j, int k) {
502 return this.a(i, j, k, true);
503 }
504
505 public int a(int i, int j, int k, boolean flag) {
506 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
507 if (flag) {
508 int l = this.getTypeId(i, j, k);
509
510 boolean check = false;
511 if (Uberbukkit.getTargetPVN() >= 12) {
512 check = l == Block.COBBLESTONE_STAIRS.id || l == Block.WOOD_STAIRS.id;
513 }
514
515 if (l == Block.STEP.id || l == Block.SOIL.id || check) {
516 int i1 = this.a(i, j + 1, k, false);
517 int j1 = this.a(i + 1, j, k, false);
518 int k1 = this.a(i - 1, j, k, false);
519 int l1 = this.a(i, j, k + 1, false);
520 int i2 = this.a(i, j, k - 1, false);
521
522 if (j1 > i1) {
523 i1 = j1;
524 }
525
526 if (k1 > i1) {
527 i1 = k1;
528 }
529
530 if (l1 > i1) {
531 i1 = l1;
532 }
533
534 if (i2 > i1) {
535 i1 = i2;
536 }
537
538 return i1;
539 }
540 }
541
542 if (j < 0) {
543 return 0;
544 } else {
545 if (j >= 128) {
546 j = 127;
547 }
548
549 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
550
551 i &= 15;
552 k &= 15;
553 return chunk.c(i, j, k, this.f);
554 }
555 } else {
556 return 15;
557 }
558 }
559
560 public boolean m(int i, int j, int k) {
561 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
562 if (j < 0) {
563 return false;
564 } else if (j >= 128) {
565 return true;
566 } else if (!this.isChunkLoaded(i >> 4, k >> 4)) {
567 return false;
568 } else {
569 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
570
571 i &= 15;
572 k &= 15;
573 return chunk.c(i, j, k);
574 }
575 } else {
576 return false;
577 }
578 }
579
580 public int getHighestBlockYAt(int i, int j) {
581 if (i >= -32000000 && j >= -32000000 && i < 32000000 && j <= 32000000) {
582 if (!this.isChunkLoaded(i >> 4, j >> 4)) {
583 return 0;
584 } else {
585 Chunk chunk = this.getChunkAt(i >> 4, j >> 4);
586
587 return chunk.b(i & 15, j & 15);
588 }
589 } else {
590 return 0;
591 }
592 }
593
594 public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l) {
595 if (!this.worldProvider.e || enumskyblock != EnumSkyBlock.SKY) {
596 if (this.isLoaded(i, j, k)) {
597 if (enumskyblock == EnumSkyBlock.SKY) {
598 if (this.m(i, j, k)) {
599 l = 15;
600 }
601 } else if (enumskyblock == EnumSkyBlock.BLOCK) {
602 int i1 = this.getTypeId(i, j, k);
603
604 if (Block.s[i1] > l) {
605 l = Block.s[i1];
606 }
607 }
608
609 if (this.a(enumskyblock, i, j, k) != l) {
610 this.a(enumskyblock, i, j, k, i, j, k);
611 }
612 }
613 }
614 }
615
616 public int a(EnumSkyBlock enumskyblock, int i, int j, int k) {
617 if (j < 0) {
618 j = 0;
619 }
620
621 if (j >= 128) {
622 j = 127;
623 }
624
625 if (j >= 0 && j < 128 && i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
626 int l = i >> 4;
627 int i1 = k >> 4;
628
629 if (!this.isChunkLoaded(l, i1)) {
630 return 0;
631 } else {
632 Chunk chunk = this.getChunkAt(l, i1);
633
634 return chunk.a(enumskyblock, i & 15, j, k & 15);
635 }
636 } else {
637 return enumskyblock.c;
638 }
639 }
640
641 public void b(EnumSkyBlock enumskyblock, int i, int j, int k, int l) {
642 if (i >= -32000000 && k >= -32000000 && i < 32000000 && k <= 32000000) {
643 if (j >= 0) {
644 if (j < 128) {
645 if (this.isChunkLoaded(i >> 4, k >> 4)) {
646 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
647
648 chunk.a(enumskyblock, i & 15, j, k & 15, l);
649
650 for (int i1 = 0; i1 < this.u.size(); ++i1) {
651 ((IWorldAccess) this.u.get(i1)).a(i, j, k);
652 }
653 }
654 }
655 }
656 }
657 }
658
659 public float n(int i, int j, int k) {
660 return this.worldProvider.f[this.getLightLevel(i, j, k)];
661 }
662
663 public boolean d() {
664 return this.f < 4;
665 }
666
667 public MovingObjectPosition a(Vec3D vec3d, Vec3D vec3d1) {
668 return this.rayTrace(vec3d, vec3d1, false, false);
669 }
670
671 public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, boolean flag) {
672 return this.rayTrace(vec3d, vec3d1, flag, false);
673 }
674
675 public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, boolean flag, boolean flag1) {
676 if (!Double.isNaN(vec3d.a) && !Double.isNaN(vec3d.b) && !Double.isNaN(vec3d.c)) {
677 if (!Double.isNaN(vec3d1.a) && !Double.isNaN(vec3d1.b) && !Double.isNaN(vec3d1.c)) {
678 int i = MathHelper.floor(vec3d1.a);
679 int j = MathHelper.floor(vec3d1.b);
680 int k = MathHelper.floor(vec3d1.c);
681 int l = MathHelper.floor(vec3d.a);
682 int i1 = MathHelper.floor(vec3d.b);
683 int j1 = MathHelper.floor(vec3d.c);
684 int k1 = this.getTypeId(l, i1, j1);
685 int l1 = this.getData(l, i1, j1);
686 Block block = Block.byId[k1];
687
688 if ((!flag1 || block == null || block.e(this, l, i1, j1) != null) && k1 > 0 && block.a(l1, flag)) {
689 MovingObjectPosition movingobjectposition = block.a(this, l, i1, j1, vec3d, vec3d1);
690
691 if (movingobjectposition != null) {
692 return movingobjectposition;
693 }
694 }
695
696 k1 = 200;
697
698 while (k1-- >= 0) {
699 if (Double.isNaN(vec3d.a) || Double.isNaN(vec3d.b) || Double.isNaN(vec3d.c)) {
700 return null;
701 }
702
703 if (l == i && i1 == j && j1 == k) {
704 return null;
705 }
706
707 boolean flag2 = true;
708 boolean flag3 = true;
709 boolean flag4 = true;
710 double d0 = 999.0D;
711 double d1 = 999.0D;
712 double d2 = 999.0D;
713
714 if (i > l) {
715 d0 = (double) l + 1.0D;
716 } else if (i < l) {
717 d0 = (double) l + 0.0D;
718 } else {
719 flag2 = false;
720 }
721
722 if (j > i1) {
723 d1 = (double) i1 + 1.0D;
724 } else if (j < i1) {
725 d1 = (double) i1 + 0.0D;
726 } else {
727 flag3 = false;
728 }
729
730 if (k > j1) {
731 d2 = (double) j1 + 1.0D;
732 } else if (k < j1) {
733 d2 = (double) j1 + 0.0D;
734 } else {
735 flag4 = false;
736 }
737
738 double d3 = 999.0D;
739 double d4 = 999.0D;
740 double d5 = 999.0D;
741 double d6 = vec3d1.a - vec3d.a;
742 double d7 = vec3d1.b - vec3d.b;
743 double d8 = vec3d1.c - vec3d.c;
744
745 if (flag2) {
746 d3 = (d0 - vec3d.a) / d6;
747 }
748
749 if (flag3) {
750 d4 = (d1 - vec3d.b) / d7;
751 }
752
753 if (flag4) {
754 d5 = (d2 - vec3d.c) / d8;
755 }
756
757 boolean flag5 = false;
758 byte b0;
759
760 if (d3 < d4 && d3 < d5) {
761 if (i > l) {
762 b0 = 4;
763 } else {
764 b0 = 5;
765 }
766
767 vec3d.a = d0;
768 vec3d.b += d7 * d3;
769 vec3d.c += d8 * d3;
770 } else if (d4 < d5) {
771 if (j > i1) {
772 b0 = 0;
773 } else {
774 b0 = 1;
775 }
776
777 vec3d.a += d6 * d4;
778 vec3d.b = d1;
779 vec3d.c += d8 * d4;
780 } else {
781 if (k > j1) {
782 b0 = 2;
783 } else {
784 b0 = 3;
785 }
786
787 vec3d.a += d6 * d5;
788 vec3d.b += d7 * d5;
789 vec3d.c = d2;
790 }
791
792 Vec3D vec3d2 = Vec3D.create(vec3d.a, vec3d.b, vec3d.c);
793
794 l = (int) (vec3d2.a = (double) MathHelper.floor(vec3d.a));
795 if (b0 == 5) {
796 --l;
797 ++vec3d2.a;
798 }
799
800 i1 = (int) (vec3d2.b = (double) MathHelper.floor(vec3d.b));
801 if (b0 == 1) {
802 --i1;
803 ++vec3d2.b;
804 }
805
806 j1 = (int) (vec3d2.c = (double) MathHelper.floor(vec3d.c));
807 if (b0 == 3) {
808 --j1;
809 ++vec3d2.c;
810 }
811
812 int i2 = this.getTypeId(l, i1, j1);
813 int j2 = this.getData(l, i1, j1);
814 Block block1 = Block.byId[i2];
815
816 if ((!flag1 || block1 == null || block1.e(this, l, i1, j1) != null) && i2 > 0 && block1.a(j2, flag)) {
817 MovingObjectPosition movingobjectposition1 = block1.a(this, l, i1, j1, vec3d, vec3d1);
818
819 if (movingobjectposition1 != null) {
820 return movingobjectposition1;
821 }
822 }
823 }
824
825 return null;
826 } else {
827 return null;
828 }
829 } else {
830 return null;
831 }
832 }
833
834 public void makeSound(Entity entity, String s, float f, float f1) {
835 for (int i = 0; i < this.u.size(); ++i) {
836 ((IWorldAccess) this.u.get(i)).a(s, entity.locX, entity.locY - (double) entity.height, entity.locZ, f, f1);
837 }
838 }
839
840 public void makeSound(double d0, double d1, double d2, String s, float f, float f1) {
841 for (int i = 0; i < this.u.size(); ++i) {
842 ((IWorldAccess) this.u.get(i)).a(s, d0, d1, d2, f, f1);
843 }
844 }
845
846 public void a(String s, int i, int j, int k) {
847 for (int l = 0; l < this.u.size(); ++l) {
848 ((IWorldAccess) this.u.get(l)).a(s, i, j, k);
849 }
850 }
851
852 public void a(String s, double d0, double d1, double d2, double d3, double d4, double d5) {
853 for (int i = 0; i < this.u.size(); ++i) {
854 ((IWorldAccess) this.u.get(i)).a(s, d0, d1, d2, d3, d4, d5);
855 }
856 }
857
858 public boolean strikeLightning(Entity entity) {
859 this.e.add(entity);
860 return true;
861 }
862
863 // CraftBukkit start - used for entities other than creatures
864 public boolean addEntity(Entity entity) {
865 return this.addEntity(entity, SpawnReason.CUSTOM); // Set reason as Custom by default
866 }
867
868
869 public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason
870 // CraftBukkit end
871 int i = MathHelper.floor(entity.locX / 16.0D);
872 int j = MathHelper.floor(entity.locZ / 16.0D);
873 boolean flag = false;
874
875 if (entity instanceof EntityHuman) {
876 flag = true;
877 }
878
879 // CraftBukkit start
880 if (entity instanceof EntityLiving && !(entity instanceof EntityPlayer)) {
881 CreatureSpawnEvent event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason);
882
883 if (event.isCancelled()) {
884 return false;
885 }
886 } else if (entity instanceof EntityItem) {
887 ItemSpawnEvent event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity);
888 if (event.isCancelled()) {
889 return false;
890 }
891 }
892 // CraftBukkit end
893
894 if (!flag && !this.isChunkLoaded(i, j)) {
895 return false;
896 } else {
897 if (entity instanceof EntityHuman) {
898 EntityHuman entityhuman = (EntityHuman) entity;
899
900 this.players.add(entityhuman);
901 this.everyoneSleeping();
902 }
903
904 this.getChunkAt(i, j).a(entity);
905 this.entityList.add(entity);
906 this.c(entity);
907 return true;
908 }
909 }
910
911 protected void c(Entity entity) {
912 for (int i = 0; i < this.u.size(); ++i) {
913 ((IWorldAccess) this.u.get(i)).a(entity);
914 }
915 }
916
917 protected void d(Entity entity) {
918 for (int i = 0; i < this.u.size(); ++i) {
919 ((IWorldAccess) this.u.get(i)).b(entity);
920 }
921 }
922
923 public void kill(Entity entity) {
924 if (entity.passenger != null) {
925 entity.passenger.mount((Entity) null);
926 }
927
928 if (entity.vehicle != null) {
929 entity.mount((Entity) null);
930 }
931
932 entity.die();
933 if (entity instanceof EntityHuman) {
934 this.players.remove((EntityHuman) entity);
935 this.everyoneSleeping();
936 }
937 }
938
939 public void removeEntity(Entity entity) {
940 entity.die();
941 if (entity instanceof EntityHuman) {
942 this.players.remove((EntityHuman) entity);
943 this.everyoneSleeping();
944 }
945
946 int i = entity.bH;
947 int j = entity.bJ;
948
949 if (entity.bG && this.isChunkLoaded(i, j)) {
950 this.getChunkAt(i, j).b(entity);
951 }
952
953 this.entityList.remove(entity);
954 this.d(entity);
955 }
956
957 public void addIWorldAccess(IWorldAccess iworldaccess) {
958 this.u.add(iworldaccess);
959 }
960
961 public List getEntities(Entity entity, AxisAlignedBB axisalignedbb) {
962 this.K.clear();
963 int i = MathHelper.floor(axisalignedbb.a);
964 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
965 int k = MathHelper.floor(axisalignedbb.b);
966 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
967 int i1 = MathHelper.floor(axisalignedbb.c);
968 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
969
970 for (int k1 = i; k1 < j; ++k1) {
971 for (int l1 = i1; l1 < j1; ++l1) {
972 if (this.isLoaded(k1, 64, l1)) {
973 for (int i2 = k - 1; i2 < l; ++i2) {
974 Block block = Block.byId[this.getTypeId(k1, i2, l1)];
975
976 if (block != null) {
977 block.a(this, k1, i2, l1, axisalignedbb, this.K);
978 }
979 }
980 }
981 }
982 }
983
984 double d0 = 0.25D;
985 List list = this.b(entity, axisalignedbb.b(d0, d0, d0));
986
987 for (int j2 = 0; j2 < list.size(); ++j2) {
988 AxisAlignedBB axisalignedbb1 = ((Entity) list.get(j2)).e_();
989
990 if (axisalignedbb1 != null && axisalignedbb1.a(axisalignedbb)) {
991 this.K.add(axisalignedbb1);
992 }
993
994 axisalignedbb1 = entity.a_((Entity) list.get(j2));
995 if (axisalignedbb1 != null && axisalignedbb1.a(axisalignedbb)) {
996 this.K.add(axisalignedbb1);
997 }
998 }
999
1000 return this.K;
1001 }
1002
1003 public int a(float f) {
1004 float f1 = this.b(f);
1005 float f2 = 1.0F - (MathHelper.cos(f1 * 3.1415927F * 2.0F) * 2.0F + 0.5F);
1006
1007 if (f2 < 0.0F) {
1008 f2 = 0.0F;
1009 }
1010
1011 if (f2 > 1.0F) {
1012 f2 = 1.0F;
1013 }
1014
1015 f2 = 1.0F - f2;
1016 f2 = (float) ((double) f2 * (1.0D - (double) (this.d(f) * 5.0F) / 16.0D));
1017 f2 = (float) ((double) f2 * (1.0D - (double) (this.c(f) * 5.0F) / 16.0D));
1018 f2 = 1.0F - f2;
1019 return (int) (f2 * 11.0F);
1020 }
1021
1022 public float b(float f) {
1023 return this.worldProvider.a(this.worldData.f(), f);
1024 }
1025
1026 public int e(int i, int j) {
1027 Chunk chunk = this.getChunkAtWorldCoords(i, j);
1028 int k = 127;
1029
1030 i &= 15;
1031
1032 for (j &= 15; k > 0; --k) {
1033 int l = chunk.getTypeId(i, k, j);
1034 Material material = l == 0 ? Material.AIR : Block.byId[l].material;
1035
1036 if (material.isSolid() || material.isLiquid()) {
1037 return k + 1;
1038 }
1039 }
1040
1041 return -1;
1042 }
1043
1044 public int f(int i, int j) {
1045 Chunk chunk = this.getChunkAtWorldCoords(i, j);
1046 int k = 127;
1047
1048 i &= 15;
1049
1050 for (j &= 15; k > 0; --k) {
1051 int l = chunk.getTypeId(i, k, j);
1052
1053 if (l != 0 && Block.byId[l].material.isSolid()) {
1054 return k + 1;
1055 }
1056 }
1057
1058 return -1;
1059 }
1060
1061 public void c(int i, int j, int k, int l, int i1) {
1062 NextTickListEntry nextticklistentry = new NextTickListEntry(i, j, k, l);
1063 byte b0 = 8;
1064
1065 if (this.a) {
1066 if (this.a(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) {
1067 int j1 = this.getTypeId(nextticklistentry.a, nextticklistentry.b, nextticklistentry.c);
1068
1069 if (j1 == nextticklistentry.d && j1 > 0) {
1070 Block.byId[j1].a(this, nextticklistentry.a, nextticklistentry.b, nextticklistentry.c, this.random);
1071 }
1072 }
1073 } else {
1074 if (this.a(i - b0, j - b0, k - b0, i + b0, j + b0, k + b0)) {
1075 if (l > 0) {
1076 nextticklistentry.a((long) i1 + this.worldData.f());
1077 }
1078
1079 if (!this.F.contains(nextticklistentry)) {
1080 this.F.add(nextticklistentry);
1081 this.E.add(nextticklistentry);
1082 }
1083 }
1084 }
1085 }
1086
1087 public void cleanUp() {
1088 int i;
1089 Entity entity;
1090
1091 for (i = 0; i < this.e.size(); ++i) {
1092 entity = (Entity) this.e.get(i);
1093 // CraftBukkit start - fixed an NPE
1094 if (entity == null) {
1095 continue;
1096 }
1097 // CraftBukkit end
1098 entity.m_();
1099 if (entity.dead) {
1100 this.e.remove(i--);
1101 }
1102 }
1103
1104 this.entityList.removeAll(this.D);
1105
1106 int j;
1107 int k;
1108
1109 for (i = 0; i < this.D.size(); ++i) {
1110 entity = (Entity) this.D.get(i);
1111 j = entity.bH;
1112 k = entity.bJ;
1113 if (entity.bG && this.isChunkLoaded(j, k)) {
1114 this.getChunkAt(j, k).b(entity);
1115 }
1116 }
1117
1118 for (i = 0; i < this.D.size(); ++i) {
1119 this.d((Entity) this.D.get(i));
1120 }
1121
1122 this.D.clear();
1123
1124 for (i = 0; i < this.entityList.size(); ++i) {
1125 entity = (Entity) this.entityList.get(i);
1126 if (entity.vehicle != null) {
1127 if (!entity.vehicle.dead && entity.vehicle.passenger == entity) {
1128 continue;
1129 }
1130
1131 entity.vehicle.passenger = null;
1132 entity.vehicle = null;
1133 }
1134
1135 if (!entity.dead) {
1136 this.playerJoinedWorld(entity);
1137 }
1138
1139 if (entity.dead) {
1140 j = entity.bH;
1141 k = entity.bJ;
1142 if (entity.bG && this.isChunkLoaded(j, k)) {
1143 this.getChunkAt(j, k).b(entity);
1144 }
1145
1146 this.entityList.remove(i--);
1147 this.d(entity);
1148 }
1149 }
1150
1151 this.L = true;
1152 Iterator iterator = this.c.iterator();
1153
1154 while (iterator.hasNext()) {
1155 TileEntity tileentity = (TileEntity) iterator.next();
1156
1157 if (!tileentity.g()) {
1158 tileentity.g_();
1159 }
1160
1161 if (tileentity.g()) {
1162 iterator.remove();
1163 Chunk chunk = this.getChunkAt(tileentity.x >> 4, tileentity.z >> 4);
1164
1165 if (chunk != null) {
1166 chunk.e(tileentity.x & 15, tileentity.y, tileentity.z & 15);
1167 }
1168 }
1169 }
1170
1171 this.L = false;
1172
1173 // Craftbukkit start
1174 if (!tileEntitiesToUnload.isEmpty()) {
1175 this.c.removeAll(tileEntitiesToUnload);
1176 this.tileEntitiesToUnload.clear();
1177 }
1178 // Craftbukkit end
1179
1180 if (!this.G.isEmpty()) {
1181 Iterator iterator1 = this.G.iterator();
1182
1183 while (iterator1.hasNext()) {
1184 TileEntity tileentity1 = (TileEntity) iterator1.next();
1185
1186 if (!tileentity1.g()) {
1187 // CraftBukkit - order matters, moved down
1188 /* if (!this.c.contains(tileentity1)) {
1189 this.c.add(tileentity1);
1190 } */
1191
1192 Chunk chunk1 = this.getChunkAt(tileentity1.x >> 4, tileentity1.z >> 4);
1193
1194 if (chunk1 != null) {
1195 chunk1.placeTileEntity(tileentity1.x & 15, tileentity1.y, tileentity1.z & 15, tileentity1);
1196 // CraftBukkit start - moved in from above
1197 if (!this.c.contains(tileentity1)) {
1198 this.c.add(tileentity1);
1199 }
1200 // CraftBukkit end
1201 }
1202
1203 this.notify(tileentity1.x, tileentity1.y, tileentity1.z);
1204 }
1205 }
1206
1207 this.G.clear();
1208 }
1209 }
1210
1211 public void a(Collection collection) {
1212 if (this.L) {
1213 this.G.addAll(collection);
1214 } else {
1215 this.c.addAll(collection);
1216 }
1217 }
1218
1219 public void playerJoinedWorld(Entity entity) {
1220 this.entityJoinedWorld(entity, true);
1221 }
1222
1223 public void entityJoinedWorld(Entity entity, boolean flag) {
1224 int i = MathHelper.floor(entity.locX);
1225 int j = MathHelper.floor(entity.locZ);
1226 byte b0 = 32;
1227
1228 if (!flag || this.a(i - b0, 0, j - b0, i + b0, 128, j + b0)) {
1229 entity.bo = entity.locX;
1230 entity.bp = entity.locY;
1231 entity.bq = entity.locZ;
1232 entity.lastYaw = entity.yaw;
1233 entity.lastPitch = entity.pitch;
1234 if (flag && entity.bG) {
1235 if (entity.vehicle != null) {
1236 entity.E();
1237 } else {
1238 entity.m_();
1239 }
1240 }
1241
1242 if (Double.isNaN(entity.locX) || Double.isInfinite(entity.locX)) {
1243 entity.locX = entity.bo;
1244 }
1245
1246 if (Double.isNaN(entity.locY) || Double.isInfinite(entity.locY)) {
1247 entity.locY = entity.bp;
1248 }
1249
1250 if (Double.isNaN(entity.locZ) || Double.isInfinite(entity.locZ)) {
1251 entity.locZ = entity.bq;
1252 }
1253
1254 if (Double.isNaN((double) entity.pitch) || Double.isInfinite((double) entity.pitch)) {
1255 entity.pitch = entity.lastPitch;
1256 }
1257
1258 if (Double.isNaN((double) entity.yaw) || Double.isInfinite((double) entity.yaw)) {
1259 entity.yaw = entity.lastYaw;
1260 }
1261
1262 int k = MathHelper.floor(entity.locX / 16.0D);
1263 int l = MathHelper.floor(entity.locY / 16.0D);
1264 int i1 = MathHelper.floor(entity.locZ / 16.0D);
1265
1266 if (!entity.bG || entity.bH != k || entity.bI != l || entity.bJ != i1) {
1267 if (entity.bG && this.isChunkLoaded(entity.bH, entity.bJ)) {
1268 this.getChunkAt(entity.bH, entity.bJ).a(entity, entity.bI);
1269 }
1270
1271 if (this.isChunkLoaded(k, i1)) {
1272 entity.bG = true;
1273 this.getChunkAt(k, i1).a(entity);
1274 } else {
1275 entity.bG = false;
1276 }
1277 }
1278
1279 if (flag && entity.bG && entity.passenger != null) {
1280 if (!entity.passenger.dead && entity.passenger.vehicle == entity) {
1281 this.playerJoinedWorld(entity.passenger);
1282 } else {
1283 entity.passenger.vehicle = null;
1284 entity.passenger = null;
1285 }
1286 }
1287 }
1288 }
1289
1290 public boolean containsEntity(AxisAlignedBB axisalignedbb) {
1291 List list = this.b((Entity) null, axisalignedbb);
1292
1293 for (int i = 0; i < list.size(); ++i) {
1294 Entity entity = (Entity) list.get(i);
1295
1296 if (!entity.dead && entity.aI) {
1297 return false;
1298 }
1299 }
1300
1301 return true;
1302 }
1303
1304 public boolean b(AxisAlignedBB axisalignedbb) {
1305 int i = MathHelper.floor(axisalignedbb.a);
1306 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
1307 int k = MathHelper.floor(axisalignedbb.b);
1308 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
1309 int i1 = MathHelper.floor(axisalignedbb.c);
1310 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
1311
1312 if (axisalignedbb.a < 0.0D) {
1313 --i;
1314 }
1315
1316 if (axisalignedbb.b < 0.0D) {
1317 --k;
1318 }
1319
1320 if (axisalignedbb.c < 0.0D) {
1321 --i1;
1322 }
1323
1324 for (int k1 = i; k1 < j; ++k1) {
1325 for (int l1 = k; l1 < l; ++l1) {
1326 for (int i2 = i1; i2 < j1; ++i2) {
1327 Block block = Block.byId[this.getTypeId(k1, l1, i2)];
1328
1329 if (block != null) {
1330 return true;
1331 }
1332 }
1333 }
1334 }
1335
1336 return false;
1337 }
1338
1339 public boolean c(AxisAlignedBB axisalignedbb) {
1340 int i = MathHelper.floor(axisalignedbb.a);
1341 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
1342 int k = MathHelper.floor(axisalignedbb.b);
1343 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
1344 int i1 = MathHelper.floor(axisalignedbb.c);
1345 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
1346
1347 if (axisalignedbb.a < 0.0D) {
1348 --i;
1349 }
1350
1351 if (axisalignedbb.b < 0.0D) {
1352 --k;
1353 }
1354
1355 if (axisalignedbb.c < 0.0D) {
1356 --i1;
1357 }
1358
1359 for (int k1 = i; k1 < j; ++k1) {
1360 for (int l1 = k; l1 < l; ++l1) {
1361 for (int i2 = i1; i2 < j1; ++i2) {
1362 Block block = Block.byId[this.getTypeId(k1, l1, i2)];
1363
1364 if (block != null && block.material.isLiquid()) {
1365 return true;
1366 }
1367 }
1368 }
1369 }
1370
1371 return false;
1372 }
1373
1374 public boolean d(AxisAlignedBB axisalignedbb) {
1375 int i = MathHelper.floor(axisalignedbb.a);
1376 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
1377 int k = MathHelper.floor(axisalignedbb.b);
1378 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
1379 int i1 = MathHelper.floor(axisalignedbb.c);
1380 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
1381
1382 if (this.a(i, k, i1, j, l, j1)) {
1383 for (int k1 = i; k1 < j; ++k1) {
1384 for (int l1 = k; l1 < l; ++l1) {
1385 for (int i2 = i1; i2 < j1; ++i2) {
1386 int j2 = this.getTypeId(k1, l1, i2);
1387
1388 if (j2 == Block.FIRE.id || j2 == Block.LAVA.id || j2 == Block.STATIONARY_LAVA.id) {
1389 return true;
1390 }
1391 }
1392 }
1393 }
1394 }
1395
1396 return false;
1397 }
1398
1399 public boolean a(AxisAlignedBB axisalignedbb, Material material, Entity entity) {
1400 int i = MathHelper.floor(axisalignedbb.a);
1401 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
1402 int k = MathHelper.floor(axisalignedbb.b);
1403 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
1404 int i1 = MathHelper.floor(axisalignedbb.c);
1405 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
1406
1407 if (!this.a(i, k, i1, j, l, j1)) {
1408 return false;
1409 } else {
1410 boolean flag = false;
1411 Vec3D vec3d = Vec3D.create(0.0D, 0.0D, 0.0D);
1412
1413 for (int k1 = i; k1 < j; ++k1) {
1414 for (int l1 = k; l1 < l; ++l1) {
1415 for (int i2 = i1; i2 < j1; ++i2) {
1416 Block block = Block.byId[this.getTypeId(k1, l1, i2)];
1417
1418 if (block != null && block.material == material) {
1419 double d0 = (double) ((float) (l1 + 1) - BlockFluids.c(this.getData(k1, l1, i2)));
1420
1421 if ((double) l >= d0) {
1422 flag = true;
1423 block.a(this, k1, l1, i2, entity, vec3d);
1424 }
1425 }
1426 }
1427 }
1428 }
1429
1430 if (vec3d.c() > 0.0D) {
1431 vec3d = vec3d.b();
1432 double d1 = 0.014D;
1433
1434 entity.motX += vec3d.a * d1;
1435 entity.motY += vec3d.b * d1;
1436 entity.motZ += vec3d.c * d1;
1437 }
1438
1439 return flag;
1440 }
1441 }
1442
1443 public boolean a(AxisAlignedBB axisalignedbb, Material material) {
1444 int i = MathHelper.floor(axisalignedbb.a);
1445 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
1446 int k = MathHelper.floor(axisalignedbb.b);
1447 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
1448 int i1 = MathHelper.floor(axisalignedbb.c);
1449 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
1450
1451 for (int k1 = i; k1 < j; ++k1) {
1452 for (int l1 = k; l1 < l; ++l1) {
1453 for (int i2 = i1; i2 < j1; ++i2) {
1454 Block block = Block.byId[this.getTypeId(k1, l1, i2)];
1455
1456 if (block != null && block.material == material) {
1457 return true;
1458 }
1459 }
1460 }
1461 }
1462
1463 return false;
1464 }
1465
1466 public boolean b(AxisAlignedBB axisalignedbb, Material material) {
1467 int i = MathHelper.floor(axisalignedbb.a);
1468 int j = MathHelper.floor(axisalignedbb.d + 1.0D);
1469 int k = MathHelper.floor(axisalignedbb.b);
1470 int l = MathHelper.floor(axisalignedbb.e + 1.0D);
1471 int i1 = MathHelper.floor(axisalignedbb.c);
1472 int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
1473
1474 for (int k1 = i; k1 < j; ++k1) {
1475 for (int l1 = k; l1 < l; ++l1) {
1476 for (int i2 = i1; i2 < j1; ++i2) {
1477 Block block = Block.byId[this.getTypeId(k1, l1, i2)];
1478
1479 if (block != null && block.material == material) {
1480 int j2 = this.getData(k1, l1, i2);
1481 double d0 = (double) (l1 + 1);
1482
1483 if (j2 < 8) {
1484 d0 = (double) (l1 + 1) - (double) j2 / 8.0D;
1485 }
1486
1487 if (d0 >= axisalignedbb.b) {
1488 return true;
1489 }
1490 }
1491 }
1492 }
1493 }
1494
1495 return false;
1496 }
1497
1498 public Explosion a(Entity entity, double d0, double d1, double d2, float f) {
1499 return this.createExplosion(entity, d0, d1, d2, f, false);
1500 }
1501
1502 //Project Poseidon Start
1503 public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag, EntityDamageEvent.DamageCause customDamageCause) {
1504 Explosion explosion = new Explosion(this, entity, d0, d1, d2, f);
1505 explosion.customDamageCause = customDamageCause;
1506
1507 explosion.setFire = flag;
1508 explosion.a();
1509 explosion.a(true);
1510 return explosion;
1511 }
1512 //Project Poseidon End
1513
1514 public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag) {
1515 Explosion explosion = new Explosion(this, entity, d0, d1, d2, f);
1516
1517 explosion.setFire = flag;
1518 explosion.a();
1519 explosion.a(true);
1520 return explosion;
1521 }
1522
1523 public float a(Vec3D vec3d, AxisAlignedBB axisalignedbb) {
1524 double d0 = 1.0D / ((axisalignedbb.d - axisalignedbb.a) * 2.0D + 1.0D);
1525 double d1 = 1.0D / ((axisalignedbb.e - axisalignedbb.b) * 2.0D + 1.0D);
1526 double d2 = 1.0D / ((axisalignedbb.f - axisalignedbb.c) * 2.0D + 1.0D);
1527 int i = 0;
1528 int j = 0;
1529
1530 for (float f = 0.0F; f <= 1.0F; f = (float) ((double) f + d0)) {
1531 for (float f1 = 0.0F; f1 <= 1.0F; f1 = (float) ((double) f1 + d1)) {
1532 for (float f2 = 0.0F; f2 <= 1.0F; f2 = (float) ((double) f2 + d2)) {
1533 double d3 = axisalignedbb.a + (axisalignedbb.d - axisalignedbb.a) * (double) f;
1534 double d4 = axisalignedbb.b + (axisalignedbb.e - axisalignedbb.b) * (double) f1;
1535 double d5 = axisalignedbb.c + (axisalignedbb.f - axisalignedbb.c) * (double) f2;
1536
1537 if (this.a(Vec3D.create(d3, d4, d5), vec3d) == null) {
1538 ++i;
1539 }
1540
1541 ++j;
1542 }
1543 }
1544 }
1545
1546 return (float) i / (float) j;
1547 }
1548
1549 public void douseFire(EntityHuman entityhuman, int i, int j, int k, int l) {
1550 if (l == 0) {
1551 --j;
1552 }
1553
1554 if (l == 1) {
1555 ++j;
1556 }
1557
1558 if (l == 2) {
1559 --k;
1560 }
1561
1562 if (l == 3) {
1563 ++k;
1564 }
1565
1566 if (l == 4) {
1567 --i;
1568 }
1569
1570 if (l == 5) {
1571 ++i;
1572 }
1573
1574 if (this.getTypeId(i, j, k) == Block.FIRE.id) {
1575 if (entityhuman != null) {
1576 BlockBreakEvent event = CraftEventFactory.callBlockBreakEvent(entityhuman, i, j, k);
1577 if (event.isCancelled()) return;
1578 }
1579 this.a(entityhuman, 1004, i, j, k, 0);
1580 this.setTypeId(i, j, k, 0);
1581 }
1582 }
1583
1584 public TileEntity getTileEntity(int i, int j, int k) {
1585 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
1586
1587 return chunk != null ? chunk.d(i & 15, j, k & 15) : null;
1588 }
1589
1590 public void setTileEntity(int i, int j, int k, TileEntity tileentity) {
1591 if (!tileentity.g()) {
1592 if (this.L) {
1593 tileentity.x = i;
1594 tileentity.y = j;
1595 tileentity.z = k;
1596 this.G.add(tileentity);
1597 } else {
1598 // CraftBukkit - order matters, moved down
1599 // this.c.add(tileentity);
1600 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
1601
1602 if (chunk != null) {
1603 chunk.placeTileEntity(i & 15, j, k & 15, tileentity);
1604 this.c.add(tileentity); // CraftBukkit - moved in from above
1605 }
1606 }
1607 }
1608 }
1609
1610 public void o(int i, int j, int k) {
1611 TileEntity tileentity = this.getTileEntity(i, j, k);
1612
1613 if (tileentity != null && this.L) {
1614 tileentity.h();
1615 } else {
1616 if (tileentity != null) {
1617 this.c.remove(tileentity);
1618 }
1619
1620 Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
1621
1622 if (chunk != null) {
1623 chunk.e(i & 15, j, k & 15);
1624 }
1625 }
1626 }
1627
1628 public boolean p(int i, int j, int k) {
1629 Block block = Block.byId[this.getTypeId(i, j, k)];
1630
1631 return block == null ? false : block.a();
1632 }
1633
1634 public boolean e(int i, int j, int k) {
1635 if (UberbukkitConfig.getInstance().getBoolean("mechanics.pre_b1_6_block_opacity", false)) {
1636 return this.p(i, j, k);
1637 }
1638 Block block = Block.byId[this.getTypeId(i, j, k)];
1639
1640 return block == null ? false : block.material.h() && block.b();
1641 }
1642
1643 public boolean doLighting() {
1644 if (this.M >= 50) {
1645 return false;
1646 } else {
1647 ++this.M;
1648
1649 boolean flag;
1650
1651 try {
1652 int i = 500;
1653
1654 while (this.C.size() > 0) {
1655 --i;
1656 if (i <= 0) {
1657 flag = true;
1658 return flag;
1659 }
1660
1661 ((MetadataChunkBlock) this.C.remove(this.C.size() - 1)).a(this);
1662 }
1663
1664 flag = false;
1665 } finally {
1666 --this.M;
1667 }
1668
1669 return flag;
1670 }
1671 }
1672
1673 public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l, int i1, int j1) {
1674 this.a(enumskyblock, i, j, k, l, i1, j1, true);
1675 }
1676
1677 public void a(EnumSkyBlock enumskyblock, int i, int j, int k, int l, int i1, int j1, boolean flag) {
1678 if (!this.worldProvider.e || enumskyblock != EnumSkyBlock.SKY) {
1679 ++A;
1680
1681 try {
1682 if (A == 50) {
1683 return;
1684 }
1685
1686 int k1 = (l + i) / 2;
1687 int l1 = (j1 + k) / 2;
1688
1689 if (this.isLoaded(k1, 64, l1)) {
1690 if (this.getChunkAtWorldCoords(k1, l1).isEmpty()) {
1691 return;
1692 }
1693
1694 int i2 = this.C.size();
1695 int j2;
1696
1697 if (flag) {
1698 j2 = 5;
1699 if (j2 > i2) {
1700 j2 = i2;
1701 }
1702
1703 for (int k2 = 0; k2 < j2; ++k2) {
1704 MetadataChunkBlock metadatachunkblock = (MetadataChunkBlock) this.C.get(this.C.size() - k2 - 1);
1705
1706 if (metadatachunkblock.a == enumskyblock && metadatachunkblock.a(i, j, k, l, i1, j1)) {
1707 return;
1708 }
1709 }
1710 }
1711
1712 this.C.add(new MetadataChunkBlock(enumskyblock, i, j, k, l, i1, j1));
1713 j2 = 1000000;
1714 if (this.C.size() > 1000000) {
1715 System.out.println("More than " + j2 + " updates, aborting lighting updates");
1716 this.C.clear();
1717 }
1718
1719 return;
1720 }
1721 } finally {
1722 --A;
1723 }
1724 }
1725 }
1726
1727 public void g() {
1728 int i = this.a(1.0F);
1729
1730 if (i != this.f) {
1731 this.f = i;
1732 }
1733 }
1734
1735 public void setSpawnFlags(boolean flag, boolean flag1) {
1736 this.allowMonsters = flag;
1737 this.allowAnimals = flag1;
1738 }
1739
1740 public void doTick() {
1741 this.i();
1742 long i;
1743
1744 if (this.everyoneDeeplySleeping()) {
1745 boolean flag = false;
1746
1747 if (this.allowMonsters && this.spawnMonsters >= 1) {
1748 flag = SpawnerCreature.a(this, this.players);
1749 }
1750
1751 if (!flag) {
1752 i = this.worldData.f() + 24000L;
1753 this.worldData.a(i - i % 24000L);
1754 this.s();
1755 }
1756 }
1757
1758 // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals
1759 if ((this.allowMonsters || this.allowAnimals) && (this instanceof WorldServer && this.getServer().getHandle().players.size() > 0)) {
1760 SpawnerCreature.spawnEntities(this, this.allowMonsters, this.allowAnimals);
1761 }
1762 // CraftBukkit end
1763
1764 this.chunkProvider.unloadChunks();
1765 int j = this.a(1.0F);
1766
1767 if (j != this.f) {
1768 this.f = j;
1769
1770 for (int k = 0; k < this.u.size(); ++k) {
1771 ((IWorldAccess) this.u.get(k)).a();
1772 }
1773 }
1774
1775 i = this.worldData.f() + 1L;
1776 if (i % (long) this.p == 0L) {
1777 this.save(false, (IProgressUpdate) null);
1778 }
1779
1780 // uberbukkit
1781 if (this.worldProvider instanceof WorldProviderHell && Uberbukkit.getTargetPVN() < 12) {
1782 this.worldData.a(18000);
1783 } else {
1784 this.worldData.a(i);
1785 }
1786
1787 this.a(false);
1788 this.j();
1789 }
1790
1791 private void x() {
1792 if (this.worldData.hasStorm()) {
1793 this.j = 1.0F;
1794 if (this.worldData.isThundering()) {
1795 this.l = 1.0F;
1796 }
1797 }
1798 }
1799
1800 protected void i() {
1801 if (!this.worldProvider.e) {
1802 if (this.m > 0) {
1803 --this.m;
1804 }
1805
1806 int i = this.worldData.getThunderDuration();
1807
1808 if (i <= 0) {
1809 if (this.worldData.isThundering()) {
1810 this.worldData.setThunderDuration(this.random.nextInt(12000) + 3600);
1811 } else {
1812 this.worldData.setThunderDuration(this.random.nextInt(168000) + 12000);
1813 }
1814 } else {
1815 --i;
1816 this.worldData.setThunderDuration(i);
1817 if (i <= 0) {
1818 // CraftBukkit start
1819 ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), !this.worldData.isThundering());
1820 this.getServer().getPluginManager().callEvent(thunder);
1821 if (!thunder.isCancelled()) {
1822 this.worldData.setThundering(!this.worldData.isThundering());
1823 }
1824 // CraftBukkit end
1825 }
1826 }
1827
1828 int j = this.worldData.getWeatherDuration();
1829
1830 if (j <= 0) {
1831 if (this.worldData.hasStorm()) {
1832 this.worldData.setWeatherDuration(this.random.nextInt(12000) + 12000);
1833 } else {
1834 this.worldData.setWeatherDuration(this.random.nextInt(168000) + 12000);
1835 }
1836 } else {
1837 --j;
1838 this.worldData.setWeatherDuration(j);
1839 if (j <= 0) {
1840 // CraftBukkit start
1841 WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), !this.worldData.hasStorm());
1842 this.getServer().getPluginManager().callEvent(weather);
1843
1844 if (!weather.isCancelled()) {
1845 this.worldData.setStorm(!this.worldData.hasStorm());
1846 }
1847 // CraftBukkit end
1848 }
1849 }
1850
1851 this.i = this.j;
1852 if (this.worldData.hasStorm()) {
1853 this.j = (float) ((double) this.j + 0.01D);
1854 } else {
1855 this.j = (float) ((double) this.j - 0.01D);
1856 }
1857
1858 if (this.j < 0.0F) {
1859 this.j = 0.0F;
1860 }
1861
1862 if (this.j > 1.0F) {
1863 this.j = 1.0F;
1864 }
1865
1866 this.k = this.l;
1867 if (this.worldData.isThundering()) {
1868 this.l = (float) ((double) this.l + 0.01D);
1869 } else {
1870 this.l = (float) ((double) this.l - 0.01D);
1871 }
1872
1873 if (this.l < 0.0F) {
1874 this.l = 0.0F;
1875 }
1876
1877 if (this.l > 1.0F) {
1878 this.l = 1.0F;
1879 }
1880 }
1881 }
1882
1883 private void y() {
1884 // CraftBukkit start
1885 WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), false);
1886 this.getServer().getPluginManager().callEvent(weather);
1887
1888 ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), false);
1889 this.getServer().getPluginManager().callEvent(thunder);
1890 if (!weather.isCancelled()) {
1891 this.worldData.setWeatherDuration(0);
1892 this.worldData.setStorm(false);
1893 }
1894 if (!thunder.isCancelled()) {
1895 this.worldData.setThunderDuration(0);
1896 this.worldData.setThundering(false);
1897 }
1898 // CraftBukkit end
1899 }
1900
1901 protected void j() {
1902 this.P.clear();
1903
1904 int i;
1905 int j;
1906 int k;
1907 int l;
1908
1909 for (int i1 = 0; i1 < this.players.size(); ++i1) {
1910 EntityHuman entityhuman = (EntityHuman) this.players.get(i1);
1911
1912 i = MathHelper.floor(entityhuman.locX / 16.0D);
1913 j = MathHelper.floor(entityhuman.locZ / 16.0D);
1914 byte b0 = 9;
1915
1916 for (k = -b0; k <= b0; ++k) {
1917 for (l = -b0; l <= b0; ++l) {
1918 this.P.add(new ChunkCoordIntPair(k + i, l + j));
1919 }
1920 }
1921 }
1922
1923 if (this.Q > 0) {
1924 --this.Q;
1925 }
1926
1927 Iterator iterator = this.P.iterator();
1928
1929 while (iterator.hasNext()) {
1930 ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next();
1931
1932 i = chunkcoordintpair.x * 16;
1933 j = chunkcoordintpair.z * 16;
1934 Chunk chunk = this.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z);
1935 int j1;
1936 int k1;
1937 int l1;
1938
1939 if (this.Q == 0) {
1940 this.g = this.g * 3 + 1013904223;
1941 k = this.g >> 2;
1942 l = k & 15;
1943 j1 = k >> 8 & 15;
1944 k1 = k >> 16 & 127;
1945 l1 = chunk.getTypeId(l, k1, j1);
1946 l += i;
1947 j1 += j;
1948 if (l1 == 0 && this.k(l, k1, j1) <= this.random.nextInt(8) && this.a(EnumSkyBlock.SKY, l, k1, j1) <= 0) {
1949 EntityHuman entityhuman1 = this.a((double) l + 0.5D, (double) k1 + 0.5D, (double) j1 + 0.5D, 8.0D);
1950
1951 if (entityhuman1 != null && entityhuman1.e((double) l + 0.5D, (double) k1 + 0.5D, (double) j1 + 0.5D) > 4.0D) {
1952 this.makeSound((double) l + 0.5D, (double) k1 + 0.5D, (double) j1 + 0.5D, "ambient.cave.cave", 0.7F, 0.8F + this.random.nextFloat() * 0.2F);
1953 this.Q = this.random.nextInt(12000) + 6000;
1954 }
1955 }
1956 }
1957
1958 if (this.random.nextInt(100000) == 0 && this.v() && this.u()) {
1959 this.g = this.g * 3 + 1013904223;
1960 k = this.g >> 2;
1961 l = i + (k & 15);
1962 j1 = j + (k >> 8 & 15);
1963 k1 = this.e(l, j1);
1964 if (this.s(l, k1, j1)) {
1965 this.strikeLightning(new EntityWeatherStorm(this, (double) l, (double) k1, (double) j1));
1966 this.m = 2;
1967 }
1968 }
1969
1970 int i2;
1971
1972 if (this.random.nextInt(16) == 0) {
1973 this.g = this.g * 3 + 1013904223;
1974 k = this.g >> 2;
1975 l = k & 15;
1976 j1 = k >> 8 & 15;
1977 k1 = this.e(l + i, j1 + j);
1978 if (this.getWorldChunkManager().getBiome(l + i, j1 + j).c() && k1 >= 0 && k1 < 128 && chunk.a(EnumSkyBlock.BLOCK, l, k1, j1) < 10) {
1979 l1 = chunk.getTypeId(l, k1 - 1, j1);
1980 i2 = chunk.getTypeId(l, k1, j1);
1981 if (this.v() && i2 == 0 && Block.SNOW.canPlace(this, l + i, k1, j1 + j) && l1 != 0 && l1 != Block.ICE.id && Block.byId[l1].material.isSolid()) {
1982 // CraftBukkit start
1983 BlockState blockState = this.getWorld().getBlockAt(l + i, k1, j1 + j).getState();
1984 blockState.setTypeId(Block.SNOW.id);
1985
1986 BlockFormEvent snow = new BlockFormEvent(blockState.getBlock(), blockState);
1987 this.getServer().getPluginManager().callEvent(snow);
1988 if (!snow.isCancelled()) {
1989 blockState.update(true);
1990 }
1991 // CraftBukkit end
1992 }
1993
1994 // uberbukkit
1995 boolean blocked = UberbukkitConfig.getInstance().getBoolean("mechanics.ice_generate_only_when_snowing", false) && !this.v();
1996
1997 // CraftBukkit start
1998 if (!blocked && l1 == Block.STATIONARY_WATER.id && chunk.getData(l, k1 - 1, j1) == 0) {
1999 BlockState blockState = this.getWorld().getBlockAt(l + i, k1 - 1, j1 + j).getState();
2000 blockState.setTypeId(Block.ICE.id);
2001
2002 BlockFormEvent iceBlockForm = new BlockFormEvent(blockState.getBlock(), blockState);
2003 this.getServer().getPluginManager().callEvent(iceBlockForm);
2004 if (!iceBlockForm.isCancelled()) {
2005 blockState.update(true);
2006 }
2007 }
2008 // CraftBukkit end
2009 }
2010 }
2011
2012 for (k = 0; k < 80; ++k) {
2013 this.g = this.g * 3 + 1013904223;
2014 l = this.g >> 2;
2015 j1 = l & 15;
2016 k1 = l >> 8 & 15;
2017 l1 = l >> 16 & 127;
2018 i2 = chunk.b[j1 << 11 | k1 << 7 | l1] & 255;
2019 if (Block.n[i2]) {
2020 Block.byId[i2].a(this, j1 + i, l1, k1 + j, this.random);
2021 }
2022 }
2023 }
2024 }
2025
2026 public boolean a(boolean flag) {
2027 int i = this.E.size();
2028
2029 if (i != this.F.size()) {
2030 throw new IllegalStateException("TickNextTick list out of synch");
2031 } else {
2032 if (i > 1000) {
2033 i = 1000;
2034 }
2035
2036 for (int j = 0; j < i; ++j) {
2037 NextTickListEntry nextticklistentry = (NextTickListEntry) this.E.first();
2038
2039 if (!flag && nextticklistentry.e > this.worldData.f()) {
2040 break;
2041 }
2042
2043 this.E.remove(nextticklistentry);
2044 this.F.remove(nextticklistentry);
2045 byte b0 = 8;
2046
2047 if (this.a(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) {
2048 int k = this.getTypeId(nextticklistentry.a, nextticklistentry.b, nextticklistentry.c);
2049
2050 if (k == nextticklistentry.d && k > 0) {
2051 Block.byId[k].a(this, nextticklistentry.a, nextticklistentry.b, nextticklistentry.c, this.random);
2052 }
2053 }
2054 }
2055
2056 return this.E.size() != 0;
2057 }
2058 }
2059
2060 public List b(Entity entity, AxisAlignedBB axisalignedbb) {
2061 this.R.clear();
2062 int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D);
2063 int j = MathHelper.floor((axisalignedbb.d + 2.0D) / 16.0D);
2064 int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D);
2065 int l = MathHelper.floor((axisalignedbb.f + 2.0D) / 16.0D);
2066
2067 for (int i1 = i; i1 <= j; ++i1) {
2068 for (int j1 = k; j1 <= l; ++j1) {
2069 if (this.isChunkLoaded(i1, j1)) {
2070 this.getChunkAt(i1, j1).a(entity, axisalignedbb, this.R);
2071 }
2072 }
2073 }
2074
2075 return this.R;
2076 }
2077
2078 public List a(Class oclass, AxisAlignedBB axisalignedbb) {
2079 int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D);
2080 int j = MathHelper.floor((axisalignedbb.d + 2.0D) / 16.0D);
2081 int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D);
2082 int l = MathHelper.floor((axisalignedbb.f + 2.0D) / 16.0D);
2083 ArrayList arraylist = new ArrayList();
2084
2085 for (int i1 = i; i1 <= j; ++i1) {
2086 for (int j1 = k; j1 <= l; ++j1) {
2087 if (this.isChunkLoaded(i1, j1)) {
2088 this.getChunkAt(i1, j1).a(oclass, axisalignedbb, arraylist);
2089 }
2090 }
2091 }
2092
2093 return arraylist;
2094 }
2095
2096 public void b(int i, int j, int k, TileEntity tileentity) {
2097 if (this.isLoaded(i, j, k)) {
2098 this.getChunkAtWorldCoords(i, k).f();
2099 }
2100
2101 for (int l = 0; l < this.u.size(); ++l) {
2102 ((IWorldAccess) this.u.get(l)).a(i, j, k, tileentity);
2103 }
2104 }
2105
2106 public int a(Class oclass) {
2107 int i = 0;
2108
2109 for (int j = 0; j < this.entityList.size(); ++j) {
2110 Entity entity = (Entity) this.entityList.get(j);
2111
2112 if (oclass.isAssignableFrom(entity.getClass())) {
2113 ++i;
2114 }
2115 }
2116
2117 return i;
2118 }
2119
2120 public void a(List list) {
2121 // CraftBukkit start
2122 Entity entity = null;
2123 for (int i = 0; i < list.size(); ++i) {
2124 entity = (Entity) list.get(i);
2125 // CraftBukkit start - fixed an NPE
2126 if (entity == null) {
2127 continue;
2128 }
2129 // CraftBukkit end
2130 this.entityList.add(entity);
2131 // CraftBukkit end
2132 this.c((Entity) list.get(i));
2133 }
2134 }
2135
2136 public void b(List list) {
2137 this.D.addAll(list);
2138 }
2139
2140 public boolean a(int i, int j, int k, int l, boolean flag, int i1) {
2141 int j1 = this.getTypeId(j, k, l);
2142 Block block = Block.byId[j1];
2143 Block block1 = Block.byId[i];
2144 AxisAlignedBB axisalignedbb = block1.e(this, j, k, l);
2145
2146 if (flag) {
2147 axisalignedbb = null;
2148 }
2149
2150 boolean defaultReturn; // CraftBukkit - store the default action
2151
2152 if (axisalignedbb != null && !this.containsEntity(axisalignedbb)) {
2153 defaultReturn = false; // CraftBukkit
2154 } else {
2155 // uberbukkit - allow placing triple chests
2156 if (pre1_5_placement_rules) {
2157 defaultReturn = (block != Block.WATER && block != Block.STATIONARY_WATER && block != Block.LAVA && block != Block.STATIONARY_LAVA && block != Block.FIRE && block != Block.SNOW ? i > 0 && block == null && block1.canPlace(this, j, k, l) : true);
2158 } else {
2159 if (block == Block.WATER || block == Block.STATIONARY_WATER || block == Block.LAVA || block == Block.STATIONARY_LAVA || block == Block.FIRE || block == Block.SNOW) {
2160 block = null;
2161 }
2162
2163 defaultReturn = i > 0 && block == null && block1.canPlace(this, j, k, l, i1); // CraftBukkit
2164 }
2165 }
2166
2167 // CraftBukkit start
2168 BlockCanBuildEvent event = new BlockCanBuildEvent(this.getWorld().getBlockAt(j, k, l), i, defaultReturn);
2169 this.getServer().getPluginManager().callEvent(event);
2170
2171 return event.isBuildable();
2172 // CraftBukkit end
2173 }
2174
2175 public PathEntity findPath(Entity entity, Entity entity1, float f) {
2176 int i = MathHelper.floor(entity.locX);
2177 int j = MathHelper.floor(entity.locY);
2178 int k = MathHelper.floor(entity.locZ);
2179 int l = (int) (f + 16.0F);
2180 int i1 = i - l;
2181 int j1 = j - l;
2182 int k1 = k - l;
2183 int l1 = i + l;
2184 int i2 = j + l;
2185 int j2 = k + l;
2186 ChunkCache chunkcache = new ChunkCache(this, i1, j1, k1, l1, i2, j2);
2187
2188 return (new Pathfinder(chunkcache)).a(entity, entity1, f);
2189 }
2190
2191 public PathEntity a(Entity entity, int i, int j, int k, float f) {
2192 int l = MathHelper.floor(entity.locX);
2193 int i1 = MathHelper.floor(entity.locY);
2194 int j1 = MathHelper.floor(entity.locZ);
2195 int k1 = (int) (f + 8.0F);
2196 int l1 = l - k1;
2197 int i2 = i1 - k1;
2198 int j2 = j1 - k1;
2199 int k2 = l + k1;
2200 int l2 = i1 + k1;
2201 int i3 = j1 + k1;
2202 ChunkCache chunkcache = new ChunkCache(this, l1, i2, j2, k2, l2, i3);
2203
2204 return (new Pathfinder(chunkcache)).a(entity, i, j, k, f);
2205 }
2206
2207 public boolean isBlockFacePowered(int i, int j, int k, int l) {
2208 int i1 = this.getTypeId(i, j, k);
2209
2210 return i1 == 0 ? false : Block.byId[i1].d(this, i, j, k, l);
2211 }
2212
2213 public boolean isBlockPowered(int i, int j, int k) {
2214 return this.isBlockFacePowered(i, j - 1, k, 0) ? true : (this.isBlockFacePowered(i, j + 1, k, 1) ? true : (this.isBlockFacePowered(i, j, k - 1, 2) ? true : (this.isBlockFacePowered(i, j, k + 1, 3) ? true : (this.isBlockFacePowered(i - 1, j, k, 4) ? true : this.isBlockFacePowered(i + 1, j, k, 5)))));
2215 }
2216
2217 public boolean isBlockFaceIndirectlyPowered(int i, int j, int k, int l) {
2218 if (this.e(i, j, k)) {
2219 return this.isBlockPowered(i, j, k);
2220 } else {
2221 int i1 = this.getTypeId(i, j, k);
2222
2223 return i1 == 0 ? false : Block.byId[i1].a(this, i, j, k, l);
2224 }
2225 }
2226
2227 public boolean isBlockIndirectlyPowered(int i, int j, int k) {
2228 return this.isBlockFaceIndirectlyPowered(i, j - 1, k, 0) ? true : (this.isBlockFaceIndirectlyPowered(i, j + 1, k, 1) ? true : (this.isBlockFaceIndirectlyPowered(i, j, k - 1, 2) ? true : (this.isBlockFaceIndirectlyPowered(i, j, k + 1, 3) ? true : (this.isBlockFaceIndirectlyPowered(i - 1, j, k, 4) ? true : this.isBlockFaceIndirectlyPowered(i + 1, j, k, 5)))));
2229 }
2230
2231 public EntityHuman findNearbyPlayer(Entity entity, double d0) {
2232 return this.a(entity.locX, entity.locY, entity.locZ, d0);
2233 }
2234
2235 public EntityHuman a(double d0, double d1, double d2, double d3) {
2236 double d4 = -1.0D;
2237 EntityHuman entityhuman = null;
2238
2239 for (int i = 0; i < this.players.size(); ++i) {
2240 EntityHuman entityhuman1 = (EntityHuman) this.players.get(i);
2241 // CraftBukkit start - fixed an NPE
2242 if (entityhuman1 == null || entityhuman1.dead) {
2243 continue;
2244 }
2245 // CraftBukkit end
2246 double d5 = entityhuman1.e(d0, d1, d2);
2247
2248 if ((d3 < 0.0D || d5 < d3 * d3) && (d4 == -1.0D || d5 < d4)) {
2249 d4 = d5;
2250 entityhuman = entityhuman1;
2251 }
2252 }
2253
2254 return entityhuman;
2255 }
2256
2257 public EntityHuman a(String s) {
2258 for (int i = 0; i < this.players.size(); ++i) {
2259 if (s.equals(((EntityHuman) this.players.get(i)).name)) {
2260 return (EntityHuman) this.players.get(i);
2261 }
2262 }
2263
2264 return null;
2265 }
2266
2267 public byte[] getMultiChunkData(int i, int j, int k, int l, int i1, int j1) {
2268 byte[] abyte = new byte[l * i1 * j1 * 5 / 2];
2269 int k1 = i >> 4;
2270 int l1 = k >> 4;
2271 int i2 = i + l - 1 >> 4;
2272 int j2 = k + j1 - 1 >> 4;
2273 int k2 = 0;
2274 int l2 = j;
2275 int i3 = j + i1;
2276
2277 if (j < 0) {
2278 l2 = 0;
2279 }
2280
2281 if (i3 > 128) {
2282 i3 = 128;
2283 }
2284
2285 for (int j3 = k1; j3 <= i2; ++j3) {
2286 int k3 = i - j3 * 16;
2287 int l3 = i + l - j3 * 16;
2288
2289 if (k3 < 0) {
2290 k3 = 0;
2291 }
2292
2293 if (l3 > 16) {
2294 l3 = 16;
2295 }
2296
2297 for (int i4 = l1; i4 <= j2; ++i4) {
2298 int j4 = k - i4 * 16;
2299 int k4 = k + j1 - i4 * 16;
2300
2301 if (j4 < 0) {
2302 j4 = 0;
2303 }
2304
2305 if (k4 > 16) {
2306 k4 = 16;
2307 }
2308
2309 k2 = this.getChunkAt(j3, i4).getData(abyte, k3, l2, j4, l3, i3, k4, k2);
2310 }
2311 }
2312
2313 return abyte;
2314 }
2315
2316 public void k() {
2317 this.w.b();
2318 }
2319
2320 public void setTime(long i) {
2321 this.worldData.a(i);
2322 }
2323
2324 public void setTimeAndFixTicklists(long i) {
2325 long j = i - this.worldData.f();
2326
2327 NextTickListEntry nextticklistentry;
2328
2329 for (Iterator iterator = this.F.iterator(); iterator.hasNext(); nextticklistentry.e += j) {
2330 nextticklistentry = (NextTickListEntry) iterator.next();
2331 }
2332
2333 this.setTime(i);
2334 }
2335
2336 public long getSeed() {
2337 return this.worldData.getSeed();
2338 }
2339
2340 public long getTime() {
2341 return this.worldData.f();
2342 }
2343
2344 public ChunkCoordinates getSpawn() {
2345 return new ChunkCoordinates(this.worldData.c(), this.worldData.d(), this.worldData.e());
2346 }
2347
2348 public boolean a(EntityHuman entityhuman, int i, int j, int k) {
2349 return true;
2350 }
2351
2352 public void a(Entity entity, byte b0) {
2353 }
2354
2355 public IChunkProvider o() {
2356 return this.chunkProvider;
2357 }
2358
2359 public void playNote(int i, int j, int k, int l, int i1) {
2360 int j1 = this.getTypeId(i, j, k);
2361
2362 if (j1 > 0) {
2363 Block.byId[j1].a(this, i, j, k, l, i1);
2364 }
2365 }
2366
2367 public IDataManager p() {
2368 return this.w;
2369 }
2370
2371 public WorldData q() {
2372 return this.worldData;
2373 }
2374
2375 public void everyoneSleeping() {
2376 this.J = !this.players.isEmpty();
2377 Iterator iterator = this.players.iterator();
2378
2379 while (iterator.hasNext()) {
2380 EntityHuman entityhuman = (EntityHuman) iterator.next();
2381
2382 // CraftBukkit
2383 if (!entityhuman.isSleeping() && !entityhuman.fauxSleeping) {
2384 this.J = false;
2385 break;
2386 }
2387 }
2388 }
2389
2390 // CraftBukkit start
2391 // Calls the method that checks to see if players are sleeping
2392 // Called by CraftPlayer.setPermanentSleeping()
2393 public void checkSleepStatus() {
2394 if (!this.isStatic) {
2395 this.everyoneSleeping();
2396 }
2397 }
2398 // CraftBukkit end
2399
2400 protected void s() {
2401 this.J = false;
2402 Iterator iterator = this.players.iterator();
2403
2404 while (iterator.hasNext()) {
2405 EntityHuman entityhuman = (EntityHuman) iterator.next();
2406
2407 if (entityhuman.isSleeping()) {
2408 entityhuman.a(false, false, true);
2409 }
2410 }
2411
2412 this.y();
2413 }
2414
2415 public boolean everyoneDeeplySleeping() {
2416 if (this.J && !this.isStatic) {
2417 Iterator iterator = this.players.iterator();
2418
2419 // CraftBukkit - This allows us to assume that some people are in bed but not really, allowing time to pass in spite of AFKers
2420 boolean foundActualSleepers = false;
2421
2422 EntityHuman entityhuman;
2423
2424 do {
2425 if (!iterator.hasNext()) {
2426 // CraftBukkit
2427 return foundActualSleepers;
2428 }
2429
2430 entityhuman = (EntityHuman) iterator.next();
2431 // CraftBukkit start
2432 if (entityhuman.isDeeplySleeping()) {
2433 foundActualSleepers = true;
2434 }
2435 } while (entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping);
2436 // CraftBukkit end
2437
2438 return false;
2439 } else {
2440 return false;
2441 }
2442 }
2443
2444 public float c(float f) {
2445 return (this.k + (this.l - this.k) * f) * this.d(f);
2446 }
2447
2448 public float d(float f) {
2449 return this.i + (this.j - this.i) * f;
2450 }
2451
2452 public boolean u() {
2453 return (double) this.c(1.0F) > 0.9D;
2454 }
2455
2456 public boolean v() {
2457 // uberbukkit
2458 if (UberbukkitConfig.getInstance().getBoolean("mechanics.do_weather", true))
2459 return (double) this.d(1.0F) > 0.2D;
2460
2461 return false;
2462 }
2463
2464 public boolean s(int i, int j, int k) {
2465 if (!this.v()) {
2466 return false;
2467 } else if (!this.isChunkLoaded(i, j, k)) {
2468 return false;
2469 } else if (this.e(i, k) > j) {
2470 return false;
2471 } else {
2472 BiomeBase biomebase = this.getWorldChunkManager().getBiome(i, k);
2473
2474 return biomebase.c() ? false : biomebase.d();
2475 }
2476 }
2477
2478 public void a(String s, WorldMapBase worldmapbase) {
2479 this.worldMaps.a(s, worldmapbase);
2480 }
2481
2482 public WorldMapBase a(Class oclass, String s) {
2483 return this.worldMaps.a(oclass, s);
2484 }
2485
2486 public int b(String s) {
2487 return this.worldMaps.a(s);
2488 }
2489
2490 public void e(int i, int j, int k, int l, int i1) {
2491 this.a((EntityHuman) null, i, j, k, l, i1);
2492 }
2493
2494 public void a(EntityHuman entityhuman, int i, int j, int k, int l, int i1) {
2495 for (int j1 = 0; j1 < this.u.size(); ++j1) {
2496 ((IWorldAccess) this.u.get(j1)).a(entityhuman, i, j, k, l, i1);
2497 }
2498 }
2499
2500 // CraftBukkit start
2501 public UUID getUUID() {
2502 return this.w.getUUID();
2503 }
2504 // CraftBukkit end
2505}