Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package org.bukkit.craftbukkit;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Random;
6import java.util.UUID;
7
8import org.bukkit.BlockChangeDelegate;
9import org.bukkit.Bukkit;
10import org.bukkit.Chunk;
11import org.bukkit.ChunkSnapshot;
12import org.bukkit.Effect;
13import org.bukkit.Location;
14import org.bukkit.TreeType;
15import org.bukkit.World;
16import org.bukkit.block.Biome;
17import org.bukkit.block.Block;
18import org.bukkit.craftbukkit.entity.CraftEntity;
19import org.bukkit.craftbukkit.entity.CraftItem;
20import org.bukkit.craftbukkit.entity.CraftLightningStrike;
21import org.bukkit.craftbukkit.entity.CraftMinecart;
22import org.bukkit.craftbukkit.entity.CraftPlayer;
23import org.bukkit.entity.Arrow;
24import org.bukkit.entity.Boat;
25import org.bukkit.entity.Chicken;
26import org.bukkit.entity.Cow;
27import org.bukkit.entity.CreatureType;
28import org.bukkit.entity.Creeper;
29import org.bukkit.entity.Egg;
30import org.bukkit.entity.Entity;
31import org.bukkit.entity.FallingSand;
32import org.bukkit.entity.Fireball;
33import org.bukkit.entity.Fish;
34import org.bukkit.entity.Ghast;
35import org.bukkit.entity.LightningStrike;
36import org.bukkit.entity.LivingEntity;
37import org.bukkit.entity.Minecart;
38import org.bukkit.entity.Painting;
39import org.bukkit.entity.Pig;
40import org.bukkit.entity.PigZombie;
41import org.bukkit.entity.Player;
42import org.bukkit.entity.PoweredMinecart;
43import org.bukkit.entity.Sheep;
44import org.bukkit.entity.Skeleton;
45import org.bukkit.entity.Slime;
46import org.bukkit.entity.Snowball;
47import org.bukkit.entity.Spider;
48import org.bukkit.entity.Squid;
49import org.bukkit.entity.StorageMinecart;
50import org.bukkit.entity.TNTPrimed;
51import org.bukkit.entity.Weather;
52import org.bukkit.entity.Wolf;
53import org.bukkit.entity.Zombie;
54import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
55import org.bukkit.event.entity.EntityDamageEvent;
56import org.bukkit.event.weather.ThunderChangeEvent;
57import org.bukkit.event.weather.WeatherChangeEvent;
58import org.bukkit.event.world.SpawnChangeEvent;
59import org.bukkit.generator.BlockPopulator;
60import org.bukkit.generator.ChunkGenerator;
61import org.bukkit.inventory.ItemStack;
62import org.bukkit.util.Vector;
63
64import net.minecraft.server.BiomeBase;
65import net.minecraft.server.ChunkCoordinates;
66import net.minecraft.server.EntityArrow;
67import net.minecraft.server.EntityBoat;
68import net.minecraft.server.EntityChicken;
69import net.minecraft.server.EntityCow;
70import net.minecraft.server.EntityCreeper;
71import net.minecraft.server.EntityEgg;
72import net.minecraft.server.EntityFallingSand;
73import net.minecraft.server.EntityFireball;
74import net.minecraft.server.EntityFish;
75import net.minecraft.server.EntityGhast;
76import net.minecraft.server.EntityItem;
77import net.minecraft.server.EntityLiving;
78import net.minecraft.server.EntityMinecart;
79import net.minecraft.server.EntityPig;
80import net.minecraft.server.EntityPigZombie;
81import net.minecraft.server.EntitySheep;
82import net.minecraft.server.EntitySkeleton;
83import net.minecraft.server.EntitySlime;
84import net.minecraft.server.EntitySnowball;
85import net.minecraft.server.EntitySpider;
86import net.minecraft.server.EntitySquid;
87import net.minecraft.server.EntityTNTPrimed;
88import net.minecraft.server.EntityTypes;
89import net.minecraft.server.EntityWeatherStorm;
90import net.minecraft.server.EntityWolf;
91import net.minecraft.server.EntityZombie;
92import net.minecraft.server.Packet4UpdateTime;
93import net.minecraft.server.Packet61;
94import net.minecraft.server.TileEntity;
95import net.minecraft.server.WorldGenBigTree;
96import net.minecraft.server.WorldGenForest;
97import net.minecraft.server.WorldGenTaiga1;
98import net.minecraft.server.WorldGenTaiga2;
99import net.minecraft.server.WorldGenTrees;
100import net.minecraft.server.WorldProvider;
101import net.minecraft.server.WorldServer;
102import uk.betacraft.uberbukkit.Uberbukkit;
103
104public class CraftWorld implements World {
105 private final WorldServer world;
106 private Environment environment;
107 private final CraftServer server = (CraftServer) Bukkit.getServer();
108 // private ConcurrentMap<Integer, CraftChunk> unloadedChunks = new MapMaker().weakValues().makeMap();
109 private final ChunkGenerator generator;
110 private final List<BlockPopulator> populators = new ArrayList<BlockPopulator>();
111
112 private static final Random rand = new Random();
113
114 public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) {
115 this.world = world;
116 this.generator = gen;
117
118 environment = env;
119 }
120
121// public void preserveChunk(CraftChunk chunk) {
122// chunk.breakLink();
123// unloadedChunks.put((chunk.getX() << 16) + chunk.getZ(), chunk);
124// }
125//
126// public Chunk popPreservedChunk(int x, int z) {
127// return unloadedChunks.remove((x << 16) + z);
128// }
129
130 public Block getBlockAt(int x, int y, int z) {
131 return getChunkAt(x >> 4, z >> 4).getBlock(x & 0xF, y & 0x7F, z & 0xF);
132 }
133
134 public int getBlockTypeIdAt(int x, int y, int z) {
135 return world.getTypeId(x, y, z);
136 }
137
138 public int getHighestBlockYAt(int x, int z) {
139 return world.getHighestBlockYAt(x, z);
140 }
141
142 public Location getSpawnLocation() {
143 ChunkCoordinates spawn = world.getSpawn();
144 return new Location(this, spawn.x, spawn.y, spawn.z);
145 }
146
147 public boolean setSpawnLocation(int x, int y, int z) {
148 try {
149 Location previousLocation = getSpawnLocation();
150 world.worldData.setSpawn(x, y, z);
151
152 // Notify anyone who's listening.
153 SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation);
154 server.getPluginManager().callEvent(event);
155
156 return true;
157 } catch (Exception e) {
158 return false;
159 }
160 }
161
162 public Chunk getChunkAt(int x, int z) {
163 return this.world.chunkProviderServer.getChunkAt(x, z).bukkitChunk;
164 }
165
166 public Chunk getChunkAt(Block block) {
167 return getChunkAt(block.getX() >> 4, block.getZ() >> 4);
168 }
169
170 public boolean isChunkLoaded(int x, int z) {
171 return world.chunkProviderServer.isChunkLoaded(x, z);
172 }
173
174 public Chunk[] getLoadedChunks() {
175 Object[] chunks = world.chunkProviderServer.chunks.values().toArray();
176 org.bukkit.Chunk[] craftChunks = new CraftChunk[chunks.length];
177
178 for (int i = 0; i < chunks.length; i++) {
179 net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) chunks[i];
180 craftChunks[i] = chunk.bukkitChunk;
181 }
182
183 return craftChunks;
184 }
185
186 public void loadChunk(int x, int z) {
187 loadChunk(x, z, true);
188 }
189
190 public boolean unloadChunk(Chunk chunk) {
191 return unloadChunk(chunk.getX(), chunk.getZ());
192 }
193
194 public boolean unloadChunk(int x, int z) {
195 return unloadChunk(x, z, true);
196 }
197
198 public boolean unloadChunk(int x, int z, boolean save) {
199 return unloadChunk(x, z, save, false);
200 }
201
202 public boolean unloadChunkRequest(int x, int z) {
203 return unloadChunkRequest(x, z, true);
204 }
205
206 public boolean unloadChunkRequest(int x, int z, boolean safe) {
207 if (safe && isChunkInUse(x, z)) {
208 return false;
209 }
210
211 world.chunkProviderServer.queueUnload(x, z);
212
213 return true;
214 }
215
216 public boolean unloadChunk(int x, int z, boolean save, boolean safe) {
217 if (safe && isChunkInUse(x, z)) {
218 return false;
219 }
220
221 net.minecraft.server.Chunk chunk = world.chunkProviderServer.getOrCreateChunk(x, z);
222
223 if (save && !chunk.isEmpty()) {
224 chunk.removeEntities();
225 world.chunkProviderServer.saveChunk(chunk);
226 world.chunkProviderServer.saveChunkNOP(chunk);
227 }
228
229// preserveChunk((CraftChunk) chunk.bukkitChunk);
230 world.chunkProviderServer.unloadQueue.remove(x, z);
231 world.chunkProviderServer.chunks.remove(x, z);
232 world.chunkProviderServer.chunkList.remove(chunk);
233
234 return true;
235 }
236
237 public boolean regenerateChunk(int x, int z) {
238 unloadChunk(x, z, false, false);
239
240 world.chunkProviderServer.unloadQueue.remove(x, z);
241
242 net.minecraft.server.Chunk chunk = null;
243
244 if (world.chunkProviderServer.chunkProvider == null) {
245 chunk = world.chunkProviderServer.emptyChunk;
246 } else {
247 chunk = world.chunkProviderServer.chunkProvider.getOrCreateChunk(x, z);
248 }
249
250 chunkLoadPostProcess(chunk, x, z);
251
252 refreshChunk(x, z);
253
254 return chunk != null;
255 }
256
257 public boolean refreshChunk(int x, int z) {
258 if (!isChunkLoaded(x, z)) {
259 return false;
260 }
261
262 int px = x << 4;
263 int pz = z << 4;
264
265 // If there are more than 10 updates to a chunk at once, it carries out the update as a cuboid
266 // This flags 16 blocks in a line along the bottom for update and then flags a block at the opposite corner at the top
267 // The cuboid that contains these 17 blocks covers the entire chunk
268 // The server will compress the chunk and send it to all clients
269
270 for (int xx = px; xx < (px + 16); xx++) {
271 world.notify(xx, 0, pz);
272 }
273 world.notify(px, 127, pz + 15);
274
275 return true;
276 }
277
278
279 public boolean isChunkInUse(int x, int z) {
280 Player[] players = server.getOnlinePlayers();
281
282 for (Player player : players) {
283 Location loc = player.getLocation();
284 if (loc.getWorld() != world.chunkProviderServer.world.getWorld()) {
285 continue;
286 }
287
288 // If the chunk is within 256 blocks of a player, refuse to accept the unload request
289 // This is larger than the distance of loaded chunks that actually surround a player
290 // The player is the center of a 21x21 chunk grid, so the edge is 10 chunks (160 blocks) away from the player
291 if (Math.abs(loc.getBlockX() - (x << 4)) <= 256 && Math.abs(loc.getBlockZ() - (z << 4)) <= 256) {
292 return true;
293 }
294 }
295 return false;
296 }
297
298 public boolean loadChunk(int x, int z, boolean generate) {
299 if (generate) {
300 // Use the default variant of loadChunk when generate == true.
301 return world.chunkProviderServer.getChunkAt(x, z) != null;
302 }
303
304 world.chunkProviderServer.unloadQueue.remove(x, z);
305 net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) world.chunkProviderServer.chunks.get(x, z);
306
307 if (chunk == null) {
308 chunk = world.chunkProviderServer.loadChunk(x, z);
309
310 chunkLoadPostProcess(chunk, x, z);
311 }
312 return chunk != null;
313 }
314
315 @SuppressWarnings("unchecked")
316 private void chunkLoadPostProcess(net.minecraft.server.Chunk chunk, int x, int z) {
317 if (chunk != null) {
318 world.chunkProviderServer.chunks.put(x, z, chunk);
319 world.chunkProviderServer.chunkList.add(chunk);
320
321 chunk.loadNOP();
322 chunk.addEntities();
323
324 if (!chunk.done && world.chunkProviderServer.isChunkLoaded(x + 1, z + 1) && world.chunkProviderServer.isChunkLoaded(x, z + 1) && world.chunkProviderServer.isChunkLoaded(x + 1, z)) {
325 world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x, z);
326 }
327
328 if (world.chunkProviderServer.isChunkLoaded(x - 1, z) && !world.chunkProviderServer.getOrCreateChunk(x - 1, z).done && world.chunkProviderServer.isChunkLoaded(x - 1, z + 1) && world.chunkProviderServer.isChunkLoaded(x, z + 1) && world.chunkProviderServer.isChunkLoaded(x - 1, z)) {
329 world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x - 1, z);
330 }
331
332 if (world.chunkProviderServer.isChunkLoaded(x, z - 1) && !world.chunkProviderServer.getOrCreateChunk(x, z - 1).done && world.chunkProviderServer.isChunkLoaded(x + 1, z - 1) && world.chunkProviderServer.isChunkLoaded(x, z - 1) && world.chunkProviderServer.isChunkLoaded(x + 1, z)) {
333 world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x, z - 1);
334 }
335
336 if (world.chunkProviderServer.isChunkLoaded(x - 1, z - 1) && !world.chunkProviderServer.getOrCreateChunk(x - 1, z - 1).done && world.chunkProviderServer.isChunkLoaded(x - 1, z - 1) && world.chunkProviderServer.isChunkLoaded(x, z - 1) && world.chunkProviderServer.isChunkLoaded(x - 1, z)) {
337 world.chunkProviderServer.getChunkAt(world.chunkProviderServer, x - 1, z - 1);
338 }
339 }
340 }
341
342 public boolean isChunkLoaded(Chunk chunk) {
343 return isChunkLoaded(chunk.getX(), chunk.getZ());
344 }
345
346 public void loadChunk(Chunk chunk) {
347 loadChunk(chunk.getX(), chunk.getZ());
348 ((CraftChunk) getChunkAt(chunk.getX(), chunk.getZ())).getHandle().bukkitChunk = chunk;
349 }
350
351 public WorldServer getHandle() {
352 return world;
353 }
354
355 public org.bukkit.entity.Item dropItem(Location loc, ItemStack item) {
356 // uberbukkit
357 if (!Uberbukkit.getProtocolHandler().canReceiveBlockItem(item.getTypeId())) {
358 return null;
359 }
360
361 net.minecraft.server.ItemStack stack = new net.minecraft.server.ItemStack(item.getTypeId(), item.getAmount(), item.getDurability());
362 EntityItem entity = new EntityItem(world, loc.getX(), loc.getY(), loc.getZ(), stack);
363 entity.pickupDelay = 10;
364 world.addEntity(entity);
365 // TODO this is inconsistent with how Entity.getBukkitEntity() works.
366 // However, this entity is not at the moment backed by a server entity class so it may be left.
367 return new CraftItem(world.getServer(), entity);
368 }
369
370 public org.bukkit.entity.Item dropItemNaturally(Location loc, ItemStack item) {
371 double xs = world.random.nextFloat() * 0.7F + (1.0F - 0.7F) * 0.5D;
372 double ys = world.random.nextFloat() * 0.7F + (1.0F - 0.7F) * 0.5D;
373 double zs = world.random.nextFloat() * 0.7F + (1.0F - 0.7F) * 0.5D;
374 loc = loc.clone();
375 loc.setX(loc.getX() + xs);
376 loc.setY(loc.getY() + ys);
377 loc.setZ(loc.getZ() + zs);
378 return dropItem(loc, item);
379 }
380
381 public Arrow spawnArrow(Location loc, Vector velocity, float speed, float spread) {
382 EntityArrow arrow = new EntityArrow(world);
383 arrow.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), 0, 0);
384 world.addEntity(arrow);
385 arrow.a(velocity.getX(), velocity.getY(), velocity.getZ(), speed, spread);
386 return (Arrow) arrow.getBukkitEntity();
387 }
388
389 public LivingEntity spawnCreature(Location loc, CreatureType creatureType) {
390 LivingEntity creature;
391 try {
392 EntityLiving entityCreature = (EntityLiving) EntityTypes.a(creatureType.getName(), world);
393 entityCreature.setPosition(loc.getX(), loc.getY(), loc.getZ());
394 creature = (LivingEntity) CraftEntity.getEntity(server, entityCreature);
395
396 // uberbukkit
397 if (!Uberbukkit.getProtocolHandler().canSeeMob(creature.getClass())) {
398 entityCreature.die();
399 return null;
400 }
401
402 world.addEntity(entityCreature, SpawnReason.CUSTOM);
403 } catch (Exception e) {
404 // if we fail, for any reason, return null.
405 creature = null;
406 }
407 return creature;
408 }
409
410 public LightningStrike strikeLightning(Location loc) {
411 EntityWeatherStorm lightning = new EntityWeatherStorm(world, loc.getX(), loc.getY(), loc.getZ());
412 world.strikeLightning(lightning);
413 return new CraftLightningStrike(server, lightning);
414 }
415
416 public LightningStrike strikeLightningEffect(Location loc) {
417 EntityWeatherStorm lightning = new EntityWeatherStorm(world, loc.getX(), loc.getY(), loc.getZ(), true);
418 world.strikeLightning(lightning);
419 return new CraftLightningStrike(server, lightning);
420 }
421
422 public boolean generateTree(Location loc, TreeType type) {
423 return generateTree(loc, type, world);
424 }
425
426 public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) {
427 switch (type) {
428 case BIG_TREE:
429 return new WorldGenBigTree().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
430 case BIRCH:
431 return new WorldGenForest().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
432 case REDWOOD:
433 return new WorldGenTaiga2().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
434 case TALL_REDWOOD:
435 return new WorldGenTaiga1().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
436 case TREE:
437 default:
438 return new WorldGenTrees().generate(delegate, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
439 }
440 }
441
442 public TileEntity getTileEntityAt(final int x, final int y, final int z) {
443 return world.getTileEntity(x, y, z);
444 }
445
446 public String getName() {
447 return world.worldData.name;
448 }
449
450 @Deprecated
451 public long getId() {
452 return world.worldData.getSeed();
453 }
454
455 public UUID getUID() {
456 return world.getUUID();
457 }
458
459 @Override
460 public String toString() {
461 return "CraftWorld{name=" + getName() + '}';
462 }
463
464 public long getTime() {
465 long time = getFullTime() % 24000;
466 if (time < 0) time += 24000;
467 return time;
468 }
469
470 public void setTime(long time) {
471 long margin = (time - getFullTime()) % 24000;
472 if (margin < 0) margin += 24000;
473 setFullTime(getFullTime() + margin);
474 }
475
476 public long getFullTime() {
477 return world.getTime();
478 }
479
480 public void setFullTime(long time) {
481 world.setTime(time);
482
483 // Forces the client to update to the new time immediately
484 for (Player p : getPlayers()) {
485 CraftPlayer cp = (CraftPlayer) p;
486 cp.getHandle().netServerHandler.sendPacket(new Packet4UpdateTime(cp.getHandle().getPlayerTime()));
487 }
488 }
489
490 public boolean createExplosion(double x, double y, double z, float power) {
491 return createExplosion(x, y, z, power, false);
492 }
493
494 public boolean createExplosion(double x, double y, double z, float power, boolean setFire) {
495 return createExplosion(x, y, z, power, setFire, EntityDamageEvent.DamageCause.PLUGIN_EXPLOSION);
496 }
497
498 public boolean createExplosion(double x, double y, double z, float power, boolean setFire, EntityDamageEvent.DamageCause customDamageCause) {
499 return world.createExplosion(null, x, y, z, power, setFire, customDamageCause).wasCanceled ? false : true;
500 }
501
502 public boolean createExplosion(Location loc, float power) {
503 return createExplosion(loc, power, false);
504 }
505
506 public boolean createExplosion(Location loc, float power, boolean setFire) {
507 return createExplosion(loc.getX(), loc.getY(), loc.getZ(), power, setFire);
508 }
509
510 public boolean createExplosion(Location loc, float power, boolean setFire, EntityDamageEvent.DamageCause customDamageCause) {
511 return createExplosion(loc.getX(), loc.getY(), loc.getZ(), power, setFire, customDamageCause);
512 }
513
514 public Environment getEnvironment() {
515 return environment;
516 }
517
518 public void setEnvironment(Environment env) {
519 if (environment != env) {
520 environment = env;
521 world.worldProvider = WorldProvider.byDimension(environment.getId());
522 }
523 }
524
525 public Block getBlockAt(Location location) {
526 return getBlockAt(location.getBlockX(), location.getBlockY(), location.getBlockZ());
527 }
528
529 public int getBlockTypeIdAt(Location location) {
530 return getBlockTypeIdAt(location.getBlockX(), location.getBlockY(), location.getBlockZ());
531 }
532
533 public int getHighestBlockYAt(Location location) {
534 return getHighestBlockYAt(location.getBlockX(), location.getBlockZ());
535 }
536
537 public Chunk getChunkAt(Location location) {
538 return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4);
539 }
540
541 public ChunkGenerator getGenerator() {
542 return generator;
543 }
544
545 public List<BlockPopulator> getPopulators() {
546 return populators;
547 }
548
549 public Block getHighestBlockAt(int x, int z) {
550 return getBlockAt(x, getHighestBlockYAt(x, z), z);
551 }
552
553 public Block getHighestBlockAt(Location location) {
554 return getHighestBlockAt(location.getBlockX(), location.getBlockZ());
555 }
556
557 public Biome getBiome(int x, int z) {
558 BiomeBase base = getHandle().getWorldChunkManager().getBiome(x, z);
559
560 if (base == BiomeBase.RAINFOREST) {
561 return Biome.RAINFOREST;
562 } else if (base == BiomeBase.SWAMPLAND) {
563 return Biome.SWAMPLAND;
564 } else if (base == BiomeBase.SEASONAL_FOREST) {
565 return Biome.SEASONAL_FOREST;
566 } else if (base == BiomeBase.FOREST) {
567 return Biome.FOREST;
568 } else if (base == BiomeBase.SAVANNA) {
569 return Biome.SAVANNA;
570 } else if (base == BiomeBase.SHRUBLAND) {
571 return Biome.SHRUBLAND;
572 } else if (base == BiomeBase.TAIGA) {
573 return Biome.TAIGA;
574 } else if (base == BiomeBase.DESERT) {
575 return Biome.DESERT;
576 } else if (base == BiomeBase.PLAINS) {
577 return Biome.PLAINS;
578 } else if (base == BiomeBase.ICE_DESERT) {
579 return Biome.ICE_DESERT;
580 } else if (base == BiomeBase.TUNDRA) {
581 return Biome.TUNDRA;
582 } else if (base == BiomeBase.HELL) {
583 return Biome.HELL;
584 } else if (base == BiomeBase.SKY) {
585 return Biome.SKY;
586 }
587
588 return null;
589 }
590
591 public double getTemperature(int x, int z) {
592 return getHandle().getWorldChunkManager().a((double[]) null, x, z, 1, 1)[0];
593 }
594
595 public double getHumidity(int x, int z) {
596 return getHandle().getWorldChunkManager().getHumidity(x, z);
597 }
598
599 public List<Entity> getEntities() {
600 List<Entity> list = new ArrayList<Entity>();
601
602 for (Object o : world.entityList) {
603 if (o instanceof net.minecraft.server.Entity) {
604 net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o;
605 Entity bukkitEntity = mcEnt.getBukkitEntity();
606
607 // Assuming that bukkitEntity isn't null
608 if (bukkitEntity != null) {
609 list.add(bukkitEntity);
610 }
611 }
612 }
613
614 return list;
615 }
616
617 public List<LivingEntity> getLivingEntities() {
618 List<LivingEntity> list = new ArrayList<LivingEntity>();
619
620 for (Object o : world.entityList) {
621 if (o instanceof net.minecraft.server.Entity) {
622 net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o;
623 Entity bukkitEntity = mcEnt.getBukkitEntity();
624
625 // Assuming that bukkitEntity isn't null
626 if (bukkitEntity != null && bukkitEntity instanceof LivingEntity) {
627 list.add((LivingEntity) bukkitEntity);
628 }
629 }
630 }
631
632 return list;
633 }
634
635 public List<Player> getPlayers() {
636 List<Player> list = new ArrayList<Player>();
637
638 for (Object o : world.entityList) {
639 if (o instanceof net.minecraft.server.Entity) {
640 net.minecraft.server.Entity mcEnt = (net.minecraft.server.Entity) o;
641 Entity bukkitEntity = mcEnt.getBukkitEntity();
642
643 if ((bukkitEntity != null) && (bukkitEntity instanceof Player)) {
644 list.add((Player) bukkitEntity);
645 }
646 }
647 }
648
649 return list;
650 }
651
652 public void save() {
653 boolean oldSave = world.canSave;
654
655 world.canSave = false;
656 world.save(true, null);
657
658 world.canSave = oldSave;
659 }
660
661 public boolean isAutoSave() {
662 return !world.canSave;
663 }
664
665 public void setAutoSave(boolean value) {
666 world.canSave = !value;
667 }
668
669 public boolean hasStorm() {
670 return world.worldData.hasStorm();
671 }
672
673 public void setStorm(boolean hasStorm) {
674 CraftServer server = world.getServer();
675
676 WeatherChangeEvent weather = new WeatherChangeEvent((org.bukkit.World) this, hasStorm);
677 server.getPluginManager().callEvent(weather);
678 if (!weather.isCancelled()) {
679 world.worldData.setStorm(hasStorm);
680
681 // These numbers are from Minecraft
682 if (hasStorm) {
683 setWeatherDuration(rand.nextInt(12000) + 12000);
684 } else {
685 setWeatherDuration(rand.nextInt(168000) + 12000);
686 }
687 }
688 }
689
690 public int getWeatherDuration() {
691 return world.worldData.getWeatherDuration();
692 }
693
694 public void setWeatherDuration(int duration) {
695 world.worldData.setWeatherDuration(duration);
696 }
697
698 public boolean isThundering() {
699 return world.worldData.isThundering();
700 }
701
702 public void setThundering(boolean thundering) {
703 CraftServer server = world.getServer();
704
705 ThunderChangeEvent thunder = new ThunderChangeEvent((org.bukkit.World) this, thundering);
706 server.getPluginManager().callEvent(thunder);
707 if (!thunder.isCancelled()) {
708 world.worldData.setThundering(thundering);
709
710 // These numbers are from Minecraft
711 if (thundering) {
712 setThunderDuration(rand.nextInt(12000) + 3600);
713 } else {
714 setThunderDuration(rand.nextInt(168000) + 12000);
715 }
716 }
717 }
718
719 public int getThunderDuration() {
720 return world.worldData.getThunderDuration();
721 }
722
723 public void setThunderDuration(int duration) {
724 world.worldData.setThunderDuration(duration);
725 }
726
727 public long getSeed() {
728 return world.worldData.getSeed();
729 }
730
731 public boolean getPVP() {
732 return world.pvpMode;
733 }
734
735 public void setPVP(boolean pvp) {
736 world.pvpMode = pvp;
737 }
738
739 public void playEffect(Player player, Effect effect, int data) {
740 playEffect(player.getLocation(), effect, data, 0);
741 }
742
743 public void playEffect(Location location, Effect effect, int data) {
744 playEffect(location, effect, data, 64);
745 }
746
747 public void playEffect(Location location, Effect effect, int data, int radius) {
748
749 int packetData = effect.getId();
750 Packet61 packet = new Packet61(packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), data);
751 int distance;
752 for (Player player : getPlayers()) {
753 distance = (int) player.getLocation().distance(location);
754 if (distance <= radius) {
755 ((CraftPlayer) player).getHandle().netServerHandler.sendPacket(packet);
756 }
757 }
758 }
759
760 @SuppressWarnings("unchecked")
761 public <T extends Entity> T spawn(Location location, Class<T> clazz) throws IllegalArgumentException {
762 if (location == null || clazz == null) {
763 throw new IllegalArgumentException("Location or entity class cannot be null");
764 }
765
766 // uberbukkit
767 if (!Uberbukkit.getProtocolHandler().canSeeMob(clazz)) {
768 return null;
769 }
770
771 net.minecraft.server.Entity entity = null;
772
773 double x = location.getX();
774 double y = location.getY();
775 double z = location.getZ();
776 float pitch = location.getPitch();
777 float yaw = location.getYaw();
778
779 // order is important for some of these
780 if (Boat.class.isAssignableFrom(clazz)) {
781 entity = new EntityBoat(world, x, y, z);
782 } else if (Egg.class.isAssignableFrom(clazz)) {
783 entity = new EntityEgg(world, x, y, z);
784 } else if (FallingSand.class.isAssignableFrom(clazz)) {
785 entity = new EntityFallingSand(world, x, y, z, 0);
786 } else if (Fireball.class.isAssignableFrom(clazz)) {
787 entity = new EntityFireball(world);
788 ((EntityFireball) entity).setPositionRotation(x, y, z, yaw, pitch);
789 Vector direction = location.getDirection().multiply(10);
790 ((EntityFireball) entity).setDirection(direction.getX(), direction.getY(), direction.getZ());
791 } else if (Snowball.class.isAssignableFrom(clazz)) {
792 entity = new EntitySnowball(world, x, y, z);
793 } else if (Minecart.class.isAssignableFrom(clazz)) {
794
795 if (PoweredMinecart.class.isAssignableFrom(clazz)) {
796 entity = new EntityMinecart(world, x, y, z, CraftMinecart.Type.PoweredMinecart.getId());
797 } else if (StorageMinecart.class.isAssignableFrom(clazz)) {
798 entity = new EntityMinecart(world, x, y, z, CraftMinecart.Type.StorageMinecart.getId());
799 } else {
800 entity = new EntityMinecart(world, x, y, z, CraftMinecart.Type.Minecart.getId());
801 }
802
803 } else if (Arrow.class.isAssignableFrom(clazz)) {
804 entity = new EntityArrow(world);
805 entity.setPositionRotation(x, y, z, 0, 0);
806 } else if (LivingEntity.class.isAssignableFrom(clazz)) {
807
808 if (Chicken.class.isAssignableFrom(clazz)) {
809 entity = new EntityChicken(world);
810 } else if (Cow.class.isAssignableFrom(clazz)) {
811 entity = new EntityCow(world);
812 } else if (Creeper.class.isAssignableFrom(clazz)) {
813 entity = new EntityCreeper(world);
814 } else if (Ghast.class.isAssignableFrom(clazz)) {
815 entity = new EntityGhast(world);
816 } else if (Pig.class.isAssignableFrom(clazz)) {
817 entity = new EntityPig(world);
818 } else if (Player.class.isAssignableFrom(clazz)) {
819 // need a net server handler for this one
820 } else if (Sheep.class.isAssignableFrom(clazz)) {
821 entity = new EntitySheep(world);
822 } else if (Skeleton.class.isAssignableFrom(clazz)) {
823 entity = new EntitySkeleton(world);
824 } else if (Slime.class.isAssignableFrom(clazz)) {
825 entity = new EntitySlime(world);
826 } else if (Spider.class.isAssignableFrom(clazz)) {
827 entity = new EntitySpider(world);
828 } else if (Squid.class.isAssignableFrom(clazz)) {
829 entity = new EntitySquid(world);
830 } else if (Wolf.class.isAssignableFrom(clazz)) {
831 entity = new EntityWolf(world);
832 } else if (PigZombie.class.isAssignableFrom(clazz)) {
833 entity = new EntityPigZombie(world);
834 } else if (Zombie.class.isAssignableFrom(clazz)) {
835 entity = new EntityZombie(world);
836 }
837
838 if (entity != null) {
839 entity.setLocation(x, y, z, pitch, yaw);
840 }
841
842 } else if (Painting.class.isAssignableFrom(clazz)) {
843 // negative
844 } else if (TNTPrimed.class.isAssignableFrom(clazz)) {
845 entity = new EntityTNTPrimed(world, x, y, z);
846 } else if (Weather.class.isAssignableFrom(clazz)) {
847 // not sure what this can do
848 entity = new EntityWeatherStorm(world, x, y, z);
849 } else if (LightningStrike.class.isAssignableFrom(clazz)) {
850 // what is this, I don't even
851 } else if (Fish.class.isAssignableFrom(clazz)) {
852 // this is not a fish, it's a bobber, and it's probably useless
853 entity = new EntityFish(world);
854 entity.setLocation(x, y, z, pitch, yaw);
855 }
856
857 if (entity != null) {
858 world.addEntity(entity);
859 return (T) entity.getBukkitEntity();
860 }
861
862 throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName());
863 }
864
865 public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, boolean includeBiomeTempRain) {
866 return CraftChunk.getEmptyChunkSnapshot(x, z, this, includeBiome, includeBiomeTempRain);
867 }
868
869 public void setSpawnFlags(boolean allowMonsters, boolean allowAnimals) {
870 world.setSpawnFlags(allowMonsters, allowAnimals);
871 }
872
873 public boolean getAllowAnimals() {
874 return world.allowAnimals;
875 }
876
877 public boolean getAllowMonsters() {
878 return world.allowMonsters;
879 }
880
881 public int getMaxHeight() {
882 return 128;
883 }
884
885 public boolean getKeepSpawnInMemory() {
886 return world.keepSpawnInMemory;
887 }
888
889 public void setKeepSpawnInMemory(boolean keepLoaded) {
890 world.keepSpawnInMemory = keepLoaded;
891 // Grab the worlds spawn chunk
892 ChunkCoordinates chunkcoordinates = this.world.getSpawn();
893 int chunkCoordX = chunkcoordinates.x >> 4;
894 int chunkCoordZ = chunkcoordinates.z >> 4;
895 // Cycle through the 25x25 Chunks around it to load/unload the chunks.
896 for (int x = -12; x <= 12; x++) {
897 for (int z = -12; z <= 12; z++) {
898 if (keepLoaded) {
899 loadChunk(chunkCoordX + x, chunkCoordZ + z);
900 } else {
901 if (isChunkLoaded(chunkCoordX + x, chunkCoordZ + z)) {
902 if (this.getHandle().getChunkAt(chunkCoordX + x, chunkCoordZ + z).isEmpty()) {
903 unloadChunk(chunkCoordX + x, chunkCoordZ + z, false);
904 } else {
905 unloadChunk(chunkCoordX + x, chunkCoordZ + z);
906 }
907 }
908 }
909 }
910 }
911 }
912}