diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java index 8d790184f4..40a2b91deb 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; // CraftBukkit start @@ -16,6 +17,7 @@ import org.bukkit.craftbukkit.util.LongHashset; import org.bukkit.craftbukkit.util.LongHashtable; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.generator.BlockPopulator; // CraftBukkit end public class ChunkProviderServer implements IChunkProvider { @@ -172,6 +174,20 @@ public class ChunkProviderServer implements IChunkProvider { chunk.done = true; if (this.chunkProvider != null) { this.chunkProvider.getChunkAt(ichunkprovider, i, j); + + // Craftbukkit start + BlockSand.a = true; + Random random = new Random(); + random.setSeed(world.getSeed()); + long xRand = random.nextLong() / 2L * 2L + 1L; + long zRand = random.nextLong() / 2L * 2L + 1L; + random.setSeed((long) i * xRand + (long) j * zRand ^ world.getSeed()); + for (BlockPopulator populator : world.getWorld().getPopulators()) { + populator.populate(world.getWorld(), random, chunk.bukkitChunk); + } + BlockSand.a = false; + // Craftbukkit end + chunk.f(); } } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index cfd527efa6..98221345b7 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -166,10 +166,10 @@ public class MinecraftServer implements Runnable, ICommandListener { int dimension = j == 0 ? 0 : -1; if (j == 0) { - world = new WorldServer(this, new ServerNBTManager(new File("."), s, true), s, dimension, i, org.bukkit.World.Environment.getEnvironment(dimension)); // CraftBukkit + world = new WorldServer(this, new ServerNBTManager(new File("."), s, true), s, dimension, i, org.bukkit.World.Environment.getEnvironment(dimension), null); // CraftBukkit } else { String name = s + "_" + Environment.getEnvironment(dimension).toString().toLowerCase(); - world = new SecondaryWorldServer(this, new ServerNBTManager(new File("."), name, true), name, dimension, i, worlds.get(0), org.bukkit.World.Environment.getEnvironment(dimension)); // CraftBukkit + world = new SecondaryWorldServer(this, new ServerNBTManager(new File("."), name, true), name, dimension, i, worlds.get(0), org.bukkit.World.Environment.getEnvironment(dimension), null); // CraftBukkit } world.tracker = new EntityTracker(this, dimension); diff --git a/src/main/java/net/minecraft/server/SecondaryWorldServer.java b/src/main/java/net/minecraft/server/SecondaryWorldServer.java index 06159cda14..d36af3f826 100644 --- a/src/main/java/net/minecraft/server/SecondaryWorldServer.java +++ b/src/main/java/net/minecraft/server/SecondaryWorldServer.java @@ -1,9 +1,11 @@ package net.minecraft.server; +import org.bukkit.generator.ChunkGenerator; + public class SecondaryWorldServer extends WorldServer { // CraftBukkit start - public SecondaryWorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, String s, int i, long j, WorldServer worldserver, org.bukkit.World.Environment env) { - super(minecraftserver, idatamanager, s, i, j, env); + public SecondaryWorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, String s, int i, long j, WorldServer worldserver, org.bukkit.World.Environment env, ChunkGenerator gen) { + super(minecraftserver, idatamanager, s, i, j, env, gen); // CraftBukkit end this.z = worldserver.z; } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index a5f954b2db..259ccdcfe6 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -9,6 +9,7 @@ import java.util.Set; import java.util.TreeSet; // CraftBukkit start +import org.bukkit.generator.ChunkGenerator; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.event.CraftEventFactory; @@ -65,12 +66,17 @@ public class World implements IBlockAccess { private int O; private List P; public boolean isStatic; + public ChunkGenerator generator; // Craftbukkit public WorldChunkManager getWorldChunkManager() { return this.worldProvider.b; } - public World(IDataManager idatamanager, String s, long i, WorldProvider worldprovider) { + // Craftbukkit start - changed signature + public World(IDataManager idatamanager, String s, long i, WorldProvider worldprovider, ChunkGenerator gen) { + this.generator = gen; + // Craftbukkit end + this.O = this.random.nextInt(12000); this.P = new ArrayList(); this.isStatic = false; @@ -118,7 +124,8 @@ public class World implements IBlockAccess { int j; - for (j = 0; !this.worldProvider.a(i, j); j += this.random.nextInt(64) - this.random.nextInt(64)) { + // Craftbukkit + for (j = 0; !canSpawn(i, j); j += this.random.nextInt(64) - this.random.nextInt(64)) { i += this.random.nextInt(64) - this.random.nextInt(64); } @@ -126,6 +133,16 @@ public class World implements IBlockAccess { this.isLoading = false; } + // Craftbukkit start + private boolean canSpawn(int x, int z) { + if (generator != null) { + return this.generator.canSpawn(((WorldServer)this).getWorld(), x, z); + } else { + return this.worldProvider.a(x, z); + } + } + // Craftbukkit end + public int a(int i, int j) { int k; diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java index cc933aeb50..14006ee8b6 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -5,8 +5,14 @@ import java.util.List; // CraftBukkit start import org.bukkit.BlockChangeDelegate; +import org.bukkit.generator.ChunkGenerator; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.generator.InternalChunkGenerator; +import org.bukkit.craftbukkit.generator.NetherChunkGenerator; +import org.bukkit.craftbukkit.generator.NormalChunkGenerator; +import org.bukkit.craftbukkit.generator.SkyLandsChunkGenerator; import org.bukkit.event.weather.LightningStrikeEvent; public class WorldServer extends World implements BlockChangeDelegate { @@ -19,13 +25,13 @@ public class WorldServer extends World implements BlockChangeDelegate { private EntityList G = new EntityList(); // CraftBukkit start - change signature - public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, String s, int i, long j, org.bukkit.World.Environment env) { - super(idatamanager, s, j, WorldProvider.a(env.getId())); + public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, String s, int i, long j, org.bukkit.World.Environment env, ChunkGenerator gen) { + super(idatamanager, s, j, WorldProvider.a(env.getId()), gen); this.server = minecraftserver; this.dimension = i; this.cserver = minecraftserver.server; - this.world = new CraftWorld(this); + this.world = new CraftWorld(this, gen); this.pvpMode = minecraftserver.pvpMode; this.manager = new PlayerManager(minecraftserver, dimension, minecraftserver.propertyManager.getInt("view-distance", 10)); } @@ -64,7 +70,22 @@ public class WorldServer extends World implements BlockChangeDelegate { protected IChunkProvider b() { IChunkLoader ichunkloader = this.w.a(this.worldProvider); - this.chunkProviderServer = new ChunkProviderServer(this, ichunkloader, this.worldProvider.b()); + // Craftbukkit start + InternalChunkGenerator gen; + + if (this.generator != null) { + gen = new CustomChunkGenerator(this, this.getSeed(), this.generator); + } else if (this.worldProvider instanceof WorldProviderHell) { + gen = new NetherChunkGenerator(this, this.getSeed()); + } else if (this.worldProvider instanceof WorldProviderSky) { + gen = new SkyLandsChunkGenerator(this, this.getSeed()); + } else { + gen = new NormalChunkGenerator(this, this.getSeed()); + } + + this.chunkProviderServer = new ChunkProviderServer(this, ichunkloader, gen); + // Craftbukkit end + return this.chunkProviderServer; } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index dd35d2453a..7696462131 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1,10 +1,12 @@ package org.bukkit.craftbukkit; +import org.bukkit.generator.ChunkGenerator; import com.avaje.ebean.config.DataSourceConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.SQLitePlatform; import com.avaje.ebeaninternal.server.lib.sql.TransactionIsolation; import net.minecraft.server.IWorldAccess; +import org.bukkit.World.Environment; import org.bukkit.command.*; import org.bukkit.entity.Player; import org.bukkit.event.world.WorldLoadEvent; @@ -54,6 +56,7 @@ import org.bukkit.craftbukkit.command.ServerCommandListener; import org.bukkit.scheduler.BukkitWorker; import org.bukkit.scheduler.BukkitTask; import org.bukkit.craftbukkit.scheduler.CraftScheduler; +import org.bukkit.event.world.WorldInitEvent; import org.bukkit.util.config.Configuration; public final class CraftServer implements Server { @@ -349,6 +352,14 @@ public final class CraftServer implements Server { } public World createWorld(String name, World.Environment environment, long seed) { + return createWorld(name, environment, seed, null); + } + + public World createWorld(String name, Environment environment, ChunkGenerator generator) { + return createWorld(name, environment, (new Random()).nextLong(), generator); + } + + public World createWorld(String name, Environment environment, long seed, ChunkGenerator generator) { File folder = new File(name); World world = getWorld(name); @@ -367,7 +378,7 @@ public final class CraftServer implements Server { } int dimension = 200 + console.worlds.size(); - WorldServer internal = new WorldServer(console, new ServerNBTManager(new File("."), name, true), name, dimension, seed, environment); + WorldServer internal = new WorldServer(console, new ServerNBTManager(new File("."), name, true), name, dimension, seed, environment, generator); internal.z = console.worlds.get(0).z; internal.tracker = new EntityTracker(console, dimension); @@ -376,6 +387,12 @@ public final class CraftServer implements Server { internal.setSpawnFlags(true, true); console.worlds.add(internal); + if (generator != null) { + internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld())); + } + + pluginManager.callEvent(new WorldInitEvent(internal.getWorld())); + short short1 = 196; long i = System.currentTimeMillis(); for (int j = -short1; j <= short1; j += 16) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index a942e743b2..33c7a95530 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -20,9 +20,11 @@ import org.bukkit.Chunk; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import org.bukkit.BlockChangeDelegate; +import org.bukkit.generator.ChunkGenerator; import org.bukkit.Location; import org.bukkit.TreeType; import org.bukkit.World; +import org.bukkit.generator.BlockPopulator; public class CraftWorld implements World { private final WorldServer world; @@ -30,13 +32,16 @@ public class CraftWorld implements World { private final CraftServer server; private final ChunkProviderServer provider; private HashMap unloadedChunks = new HashMap(); + private final ChunkGenerator generator; + private final List populators = new ArrayList(); private static final Random rand = new Random(); - public CraftWorld(WorldServer world) { + public CraftWorld(WorldServer world, ChunkGenerator gen) { this.world = world; this.server = world.getServer(); this.provider = world.chunkProviderServer; + this.generator = gen; environment = Environment.getEnvironment(world.worldProvider.dimension); @@ -463,6 +468,14 @@ public class CraftWorld implements World { return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4); } + public ChunkGenerator getGenerator() { + return generator; + } + + public List getPopulators() { + return populators; + } + private final class ChunkCoordinate { public final int x; public final int z; diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java new file mode 100644 index 0000000000..3103c5e9b9 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -0,0 +1,73 @@ +package org.bukkit.craftbukkit.generator; + +import java.util.List; +import java.util.Random; +import net.minecraft.server.Chunk; +import net.minecraft.server.IChunkProvider; +import net.minecraft.server.IProgressUpdate; +import net.minecraft.server.World; +import net.minecraft.server.WorldServer; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; + +public class CustomChunkGenerator implements InternalChunkGenerator { + private final ChunkGenerator generator; + private final WorldServer world; + private final long seed; + private final Random random; + + public CustomChunkGenerator(World world, long seed, ChunkGenerator generator) { + this.world = (WorldServer)world; + this.seed = seed; + this.generator = generator; + + this.random = new Random(seed); + } + + public boolean isChunkLoaded(int x, int z) { + return true; + } + + public Chunk getOrCreateChunk(int x, int z) { + random.setSeed((long)x * 341873128712L + (long)z * 132897987541L); + byte[] types = generator.generate(world.getWorld(), random, x, z); + + Chunk chunk = new Chunk(world, types, x, z); + + chunk.b(); + + return chunk; + } + + public void getChunkAt(IChunkProvider icp, int i, int i1) { + // Nothing! + } + + public boolean saveChunks(boolean bln, IProgressUpdate ipu) { + return true; + } + + public boolean unloadChunks() { + return false; + } + + public boolean b() { + return true; + } + + public byte[] generate(org.bukkit.World world, Random random, int x, int z) { + return generator.generate(world, random, x, z); + } + + public Chunk getChunkAt(int x, int z) { + return getOrCreateChunk(x, z); + } + + public boolean canSpawn(org.bukkit.World world, int x, int z) { + return generator.canSpawn(world, x, z); + } + + public List getDefaultPopulators(org.bukkit.World world) { + return generator.getDefaultPopulators(world); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/InternalChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/InternalChunkGenerator.java new file mode 100644 index 0000000000..d98c5e6672 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/InternalChunkGenerator.java @@ -0,0 +1,9 @@ + +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.IChunkProvider; +import org.bukkit.generator.ChunkGenerator; + +public interface InternalChunkGenerator extends ChunkGenerator, IChunkProvider { + +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/NetherChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/NetherChunkGenerator.java new file mode 100644 index 0000000000..59d7bbec55 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/NetherChunkGenerator.java @@ -0,0 +1,12 @@ +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.World; + +/** + * This class is useless. Just fyi. + */ +public class NetherChunkGenerator extends NormalChunkGenerator { + public NetherChunkGenerator(World world, long seed) { + super(world, seed); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java new file mode 100644 index 0000000000..2e83fa5c3e --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java @@ -0,0 +1,27 @@ +package org.bukkit.craftbukkit.generator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import net.minecraft.server.ChunkProviderGenerate; +import net.minecraft.server.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.generator.BlockPopulator; + +public class NormalChunkGenerator extends ChunkProviderGenerate implements InternalChunkGenerator { + public NormalChunkGenerator(World world, long seed) { + super(world, seed); + } + + public byte[] generate(org.bukkit.World world, Random random, int x, int z) { + throw new UnsupportedOperationException("Not supported."); + } + + public boolean canSpawn(org.bukkit.World world, int x, int z) { + return ((CraftWorld)world).getHandle().worldProvider.a(x, z); + } + + public List getDefaultPopulators(org.bukkit.World world) { + return new ArrayList(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/SkyLandsChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/SkyLandsChunkGenerator.java new file mode 100644 index 0000000000..e327996943 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/SkyLandsChunkGenerator.java @@ -0,0 +1,12 @@ +package org.bukkit.craftbukkit.generator; + +import net.minecraft.server.World; + +/** + * This class is useless. Just fyi. + */ +public class SkyLandsChunkGenerator extends NormalChunkGenerator { + public SkyLandsChunkGenerator(World world, long seed) { + super(world, seed); + } +}