From 5007d500210a0bf7fb1ec142b25e624acf4f7240 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Mon, 29 Feb 2016 21:09:10 -0600
Subject: [PATCH] mc-dev imports


diff --git a/src/main/java/net/minecraft/server/BaseBlockPosition.java b/src/main/java/net/minecraft/server/BaseBlockPosition.java
new file mode 100644
index 0000000..e54e7b7
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BaseBlockPosition.java
@@ -0,0 +1,93 @@
+package net.minecraft.server;
+
+import com.google.common.base.Objects;
+
+public class BaseBlockPosition implements Comparable<BaseBlockPosition> {
+
+    public static final BaseBlockPosition ZERO = new BaseBlockPosition(0, 0, 0);
+    private final int a;
+    private final int c;
+    private final int d;
+
+    public BaseBlockPosition(int i, int j, int k) {
+        this.a = i;
+        this.c = j;
+        this.d = k;
+    }
+
+    public BaseBlockPosition(double d0, double d1, double d2) {
+        this(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2));
+    }
+
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        } else if (!(object instanceof BaseBlockPosition)) {
+            return false;
+        } else {
+            BaseBlockPosition baseblockposition = (BaseBlockPosition) object;
+
+            return this.getX() != baseblockposition.getX() ? false : (this.getY() != baseblockposition.getY() ? false : this.getZ() == baseblockposition.getZ());
+        }
+    }
+
+    public int hashCode() {
+        return (this.getY() + this.getZ() * 31) * 31 + this.getX();
+    }
+
+    public int i(BaseBlockPosition baseblockposition) {
+        return this.getY() == baseblockposition.getY() ? (this.getZ() == baseblockposition.getZ() ? this.getX() - baseblockposition.getX() : this.getZ() - baseblockposition.getZ()) : this.getY() - baseblockposition.getY();
+    }
+
+    public int getX() {
+        return this.a;
+    }
+
+    public int getY() {
+        return this.c;
+    }
+
+    public int getZ() {
+        return this.d;
+    }
+
+    public BaseBlockPosition d(BaseBlockPosition baseblockposition) {
+        return new BaseBlockPosition(this.getY() * baseblockposition.getZ() - this.getZ() * baseblockposition.getY(), this.getZ() * baseblockposition.getX() - this.getX() * baseblockposition.getZ(), this.getX() * baseblockposition.getY() - this.getY() * baseblockposition.getX());
+    }
+
+    public double f(int i, int j, int k) {
+        double d0 = (double) (this.getX() - i);
+        double d1 = (double) (this.getY() - j);
+        double d2 = (double) (this.getZ() - k);
+
+        return Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
+    }
+
+    public double distanceSquared(double d0, double d1, double d2) {
+        double d3 = (double) this.getX() - d0;
+        double d4 = (double) this.getY() - d1;
+        double d5 = (double) this.getZ() - d2;
+
+        return d3 * d3 + d4 * d4 + d5 * d5;
+    }
+
+    public double f(double d0, double d1, double d2) {
+        double d3 = (double) this.getX() + 0.5D - d0;
+        double d4 = (double) this.getY() + 0.5D - d1;
+        double d5 = (double) this.getZ() + 0.5D - d2;
+
+        return d3 * d3 + d4 * d4 + d5 * d5;
+    }
+
+    public double k(BaseBlockPosition baseblockposition) {
+        return this.distanceSquared((double) baseblockposition.getX(), (double) baseblockposition.getY(), (double) baseblockposition.getZ());
+    }
+
+    public String toString() {
+        return Objects.toStringHelper(this).add("x", this.getX()).add("y", this.getY()).add("z", this.getZ()).toString();
+    }
+
+    public int compareTo(Object object) {
+        return this.i((BaseBlockPosition) object);
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BiomeBase.java b/src/main/java/net/minecraft/server/BiomeBase.java
new file mode 100644
index 0000000..be4b871
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BiomeBase.java
@@ -0,0 +1,463 @@
+package net.minecraft.server;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public abstract class BiomeBase {
+
+    private static final Logger y = LogManager.getLogger();
+    protected static final IBlockData a = Blocks.STONE.getBlockData();
+    protected static final IBlockData b = Blocks.AIR.getBlockData();
+    protected static final IBlockData c = Blocks.BEDROCK.getBlockData();
+    protected static final IBlockData d = Blocks.GRAVEL.getBlockData();
+    protected static final IBlockData e = Blocks.RED_SANDSTONE.getBlockData();
+    protected static final IBlockData f = Blocks.SANDSTONE.getBlockData();
+    protected static final IBlockData g = Blocks.ICE.getBlockData();
+    protected static final IBlockData h = Blocks.WATER.getBlockData();
+    public static final Set<BiomeBase> i = Sets.newHashSet();
+    public static final RegistryBlockID<BiomeBase> j = new RegistryBlockID();
+    protected static final NoiseGenerator3 k = new NoiseGenerator3(new Random(1234L), 1);
+    protected static final NoiseGenerator3 l = new NoiseGenerator3(new Random(2345L), 1);
+    protected static final WorldGenTallPlant m = new WorldGenTallPlant();
+    protected static final WorldGenTrees n = new WorldGenTrees(false);
+    protected static final WorldGenBigTree o = new WorldGenBigTree(false);
+    protected static final WorldGenSwampTree p = new WorldGenSwampTree();
+    public static final RegistryMaterials<MinecraftKey, BiomeBase> REGISTRY_ID = new RegistryMaterials();
+    private final String z;
+    private final float A;
+    private final float B;
+    private final float C;
+    private final float D;
+    private final int E;
+    private final boolean F;
+    private final boolean G;
+    private final String H;
+    public IBlockData r;
+    public IBlockData s;
+    public BiomeDecorator t;
+    protected List<BiomeBase.BiomeMeta> u;
+    protected List<BiomeBase.BiomeMeta> v;
+    protected List<BiomeBase.BiomeMeta> w;
+    protected List<BiomeBase.BiomeMeta> x;
+
+    public static int a(BiomeBase biomebase) {
+        return BiomeBase.REGISTRY_ID.a((Object) biomebase);
+    }
+
+    public static BiomeBase a(int i) {
+        return (BiomeBase) BiomeBase.REGISTRY_ID.getId(i);
+    }
+
+    public static BiomeBase b(BiomeBase biomebase) {
+        return (BiomeBase) BiomeBase.j.fromId(a(biomebase));
+    }
+
+    protected BiomeBase(BiomeBase.a biomebase_a) {
+        this.r = Blocks.GRASS.getBlockData();
+        this.s = Blocks.DIRT.getBlockData();
+        this.u = Lists.newArrayList();
+        this.v = Lists.newArrayList();
+        this.w = Lists.newArrayList();
+        this.x = Lists.newArrayList();
+        this.z = biomebase_a.a;
+        this.A = biomebase_a.b;
+        this.B = biomebase_a.c;
+        this.C = biomebase_a.d;
+        this.D = biomebase_a.e;
+        this.E = biomebase_a.f;
+        this.F = biomebase_a.g;
+        this.G = biomebase_a.h;
+        this.H = biomebase_a.i;
+        this.t = this.a();
+        this.v.add(new BiomeBase.BiomeMeta(EntitySheep.class, 12, 4, 4));
+        this.v.add(new BiomeBase.BiomeMeta(EntityPig.class, 10, 4, 4));
+        this.v.add(new BiomeBase.BiomeMeta(EntityChicken.class, 10, 4, 4));
+        this.v.add(new BiomeBase.BiomeMeta(EntityCow.class, 8, 4, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntitySpider.class, 100, 4, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntityZombie.class, 100, 4, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntitySkeleton.class, 100, 4, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntityCreeper.class, 100, 4, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntitySlime.class, 100, 4, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntityEnderman.class, 10, 1, 4));
+        this.u.add(new BiomeBase.BiomeMeta(EntityWitch.class, 5, 1, 1));
+        this.w.add(new BiomeBase.BiomeMeta(EntitySquid.class, 10, 4, 4));
+        this.x.add(new BiomeBase.BiomeMeta(EntityBat.class, 10, 8, 8));
+    }
+
+    protected BiomeDecorator a() {
+        return new BiomeDecorator();
+    }
+
+    public boolean b() {
+        return this.H != null;
+    }
+
+    public WorldGenTreeAbstract a(Random random) {
+        return (WorldGenTreeAbstract) (random.nextInt(10) == 0 ? BiomeBase.o : BiomeBase.n);
+    }
+
+    public WorldGenerator b(Random random) {
+        return new WorldGenGrass(BlockLongGrass.EnumTallGrassType.GRASS);
+    }
+
+    public BlockFlowers.EnumFlowerVarient a(Random random, BlockPosition blockposition) {
+        return random.nextInt(3) > 0 ? BlockFlowers.EnumFlowerVarient.DANDELION : BlockFlowers.EnumFlowerVarient.POPPY;
+    }
+
+    public List<BiomeBase.BiomeMeta> getMobs(EnumCreatureType enumcreaturetype) {
+        switch (BiomeBase.SyntheticClass_1.a[enumcreaturetype.ordinal()]) {
+        case 1:
+            return this.u;
+
+        case 2:
+            return this.v;
+
+        case 3:
+            return this.w;
+
+        case 4:
+            return this.x;
+
+        default:
+            return Collections.emptyList();
+        }
+    }
+
+    public boolean c() {
+        return this.p();
+    }
+
+    public boolean d() {
+        return this.p() ? false : this.G;
+    }
+
+    public boolean e() {
+        return this.getHumidity() > 0.85F;
+    }
+
+    public float f() {
+        return 0.1F;
+    }
+
+    public final float a(BlockPosition blockposition) {
+        if (blockposition.getY() > 64) {
+            float f = (float) (BiomeBase.k.a((double) ((float) blockposition.getX() / 8.0F), (double) ((float) blockposition.getZ() / 8.0F)) * 4.0D);
+
+            return this.getTemperature() - (f + (float) blockposition.getY() - 64.0F) * 0.05F / 30.0F;
+        } else {
+            return this.getTemperature();
+        }
+    }
+
+    public void a(World world, Random random, BlockPosition blockposition) {
+        this.t.a(world, random, this, blockposition);
+    }
+
+    public void a(World world, Random random, ChunkSnapshot chunksnapshot, int i, int j, double d0) {
+        this.b(world, random, chunksnapshot, i, j, d0);
+    }
+
+    public final void b(World world, Random random, ChunkSnapshot chunksnapshot, int i, int j, double d0) {
+        int k = world.K();
+        IBlockData iblockdata = this.r;
+        IBlockData iblockdata1 = this.s;
+        int l = -1;
+        int i1 = (int) (d0 / 3.0D + 3.0D + random.nextDouble() * 0.25D);
+        int j1 = i & 15;
+        int k1 = j & 15;
+        BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
+
+        for (int l1 = 255; l1 >= 0; --l1) {
+            if (l1 <= random.nextInt(5)) {
+                chunksnapshot.a(k1, l1, j1, BiomeBase.c);
+            } else {
+                IBlockData iblockdata2 = chunksnapshot.a(k1, l1, j1);
+
+                if (iblockdata2.getMaterial() == Material.AIR) {
+                    l = -1;
+                } else if (iblockdata2.getBlock() == Blocks.STONE) {
+                    if (l == -1) {
+                        if (i1 <= 0) {
+                            iblockdata = BiomeBase.b;
+                            iblockdata1 = BiomeBase.a;
+                        } else if (l1 >= k - 4 && l1 <= k + 1) {
+                            iblockdata = this.r;
+                            iblockdata1 = this.s;
+                        }
+
+                        if (l1 < k && (iblockdata == null || iblockdata.getMaterial() == Material.AIR)) {
+                            if (this.a((BlockPosition) blockposition_mutableblockposition.c(i, l1, j)) < 0.15F) {
+                                iblockdata = BiomeBase.g;
+                            } else {
+                                iblockdata = BiomeBase.h;
+                            }
+                        }
+
+                        l = i1;
+                        if (l1 >= k - 1) {
+                            chunksnapshot.a(k1, l1, j1, iblockdata);
+                        } else if (l1 < k - 7 - i1) {
+                            iblockdata = BiomeBase.b;
+                            iblockdata1 = BiomeBase.a;
+                            chunksnapshot.a(k1, l1, j1, BiomeBase.d);
+                        } else {
+                            chunksnapshot.a(k1, l1, j1, iblockdata1);
+                        }
+                    } else if (l > 0) {
+                        --l;
+                        chunksnapshot.a(k1, l1, j1, iblockdata1);
+                        if (l == 0 && iblockdata1.getBlock() == Blocks.SAND) {
+                            l = random.nextInt(4) + Math.max(0, l1 - 63);
+                            iblockdata1 = iblockdata1.get(BlockSand.VARIANT) == BlockSand.EnumSandVariant.RED_SAND ? BiomeBase.e : BiomeBase.f;
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    public Class<? extends BiomeBase> g() {
+        return this.getClass();
+    }
+
+    public BiomeBase.EnumTemperature h() {
+        return (double) this.getTemperature() < 0.2D ? BiomeBase.EnumTemperature.COLD : ((double) this.getTemperature() < 1.0D ? BiomeBase.EnumTemperature.MEDIUM : BiomeBase.EnumTemperature.WARM);
+    }
+
+    public static BiomeBase getBiome(int i) {
+        return getBiome(i, (BiomeBase) null);
+    }
+
+    public static BiomeBase getBiome(int i, BiomeBase biomebase) {
+        BiomeBase biomebase1 = a(i);
+
+        return biomebase1 == null ? biomebase : biomebase1;
+    }
+
+    public boolean i() {
+        return false;
+    }
+
+    public final float j() {
+        return this.A;
+    }
+
+    public final float getHumidity() {
+        return this.D;
+    }
+
+    public final String l() {
+        return this.z;
+    }
+
+    public final float m() {
+        return this.B;
+    }
+
+    public final float getTemperature() {
+        return this.C;
+    }
+
+    public final boolean p() {
+        return this.F;
+    }
+
+    public static void q() {
+        a(0, "ocean", new BiomeOcean((new BiomeBase.a("Ocean")).c(-1.0F).d(0.1F)));
+        a(1, "plains", new BiomePlains(false, (new BiomeBase.a("Plains")).c(0.125F).d(0.05F).a(0.8F).b(0.4F)));
+        a(2, "desert", new BiomeDesert((new BiomeBase.a("Desert")).c(0.125F).d(0.05F).a(2.0F).b(0.0F).a()));
+        a(3, "extreme_hills", new BiomeBigHills(BiomeBigHills.Type.NORMAL, (new BiomeBase.a("Extreme Hills")).c(1.0F).d(0.5F).a(0.2F).b(0.3F)));
+        a(4, "forest", new BiomeForest(BiomeForest.Type.NORMAL, (new BiomeBase.a("Forest")).a(0.7F).b(0.8F)));
+        a(5, "taiga", new BiomeTaiga(BiomeTaiga.Type.NORMAL, (new BiomeBase.a("Taiga")).c(0.2F).d(0.2F).a(0.25F).b(0.8F)));
+        a(6, "swampland", new BiomeSwamp((new BiomeBase.a("Swampland")).c(-0.2F).d(0.1F).a(0.8F).b(0.9F).a(14745518)));
+        a(7, "river", new BiomeRiver((new BiomeBase.a("River")).c(-0.5F).d(0.0F)));
+        a(8, "hell", new BiomeHell((new BiomeBase.a("Hell")).a(2.0F).b(0.0F).a()));
+        a(9, "sky", new BiomeTheEnd((new BiomeBase.a("The End")).a()));
+        a(10, "frozen_ocean", new BiomeOcean((new BiomeBase.a("FrozenOcean")).c(-1.0F).d(0.1F).a(0.0F).b(0.5F).b()));
+        a(11, "frozen_river", new BiomeRiver((new BiomeBase.a("FrozenRiver")).c(-0.5F).d(0.0F).a(0.0F).b(0.5F).b()));
+        a(12, "ice_flats", new BiomeIcePlains(false, (new BiomeBase.a("Ice Plains")).c(0.125F).d(0.05F).a(0.0F).b(0.5F).b()));
+        a(13, "ice_mountains", new BiomeIcePlains(false, (new BiomeBase.a("Ice Mountains")).c(0.45F).d(0.3F).a(0.0F).b(0.5F).b()));
+        a(14, "mushroom_island", new BiomeMushrooms((new BiomeBase.a("MushroomIsland")).c(0.2F).d(0.3F).a(0.9F).b(1.0F)));
+        a(15, "mushroom_island_shore", new BiomeMushrooms((new BiomeBase.a("MushroomIslandShore")).c(0.0F).d(0.025F).a(0.9F).b(1.0F)));
+        a(16, "beaches", new BiomeBeach((new BiomeBase.a("Beach")).c(0.0F).d(0.025F).a(0.8F).b(0.4F)));
+        a(17, "desert_hills", new BiomeDesert((new BiomeBase.a("DesertHills")).c(0.45F).d(0.3F).a(2.0F).b(0.0F).a()));
+        a(18, "forest_hills", new BiomeForest(BiomeForest.Type.NORMAL, (new BiomeBase.a("ForestHills")).c(0.45F).d(0.3F).a(0.7F).b(0.8F)));
+        a(19, "taiga_hills", new BiomeTaiga(BiomeTaiga.Type.NORMAL, (new BiomeBase.a("TaigaHills")).a(0.25F).b(0.8F).c(0.45F).d(0.3F)));
+        a(20, "smaller_extreme_hills", new BiomeBigHills(BiomeBigHills.Type.EXTRA_TREES, (new BiomeBase.a("Extreme Hills Edge")).c(0.8F).d(0.3F).a(0.2F).b(0.3F)));
+        a(21, "jungle", new BiomeJungle(false, (new BiomeBase.a("Jungle")).a(0.95F).b(0.9F)));
+        a(22, "jungle_hills", new BiomeJungle(false, (new BiomeBase.a("JungleHills")).c(0.45F).d(0.3F).a(0.95F).b(0.9F)));
+        a(23, "jungle_edge", new BiomeJungle(true, (new BiomeBase.a("JungleEdge")).a(0.95F).b(0.8F)));
+        a(24, "deep_ocean", new BiomeOcean((new BiomeBase.a("Deep Ocean")).c(-1.8F).d(0.1F)));
+        a(25, "stone_beach", new BiomeStoneBeach((new BiomeBase.a("Stone Beach")).c(0.1F).d(0.8F).a(0.2F).b(0.3F)));
+        a(26, "cold_beach", new BiomeBeach((new BiomeBase.a("Cold Beach")).c(0.0F).d(0.025F).a(0.05F).b(0.3F).b()));
+        a(27, "birch_forest", new BiomeForest(BiomeForest.Type.BIRCH, (new BiomeBase.a("Birch Forest")).a(0.6F).b(0.6F)));
+        a(28, "birch_forest_hills", new BiomeForest(BiomeForest.Type.BIRCH, (new BiomeBase.a("Birch Forest Hills")).c(0.45F).d(0.3F).a(0.6F).b(0.6F)));
+        a(29, "roofed_forest", new BiomeForest(BiomeForest.Type.ROOFED, (new BiomeBase.a("Roofed Forest")).a(0.7F).b(0.8F)));
+        a(30, "taiga_cold", new BiomeTaiga(BiomeTaiga.Type.NORMAL, (new BiomeBase.a("Cold Taiga")).c(0.2F).d(0.2F).a(-0.5F).b(0.4F).b()));
+        a(31, "taiga_cold_hills", new BiomeTaiga(BiomeTaiga.Type.NORMAL, (new BiomeBase.a("Cold Taiga Hills")).c(0.45F).d(0.3F).a(-0.5F).b(0.4F).b()));
+        a(32, "redwood_taiga", new BiomeTaiga(BiomeTaiga.Type.MEGA, (new BiomeBase.a("Mega Taiga")).a(0.3F).b(0.8F).c(0.2F).d(0.2F)));
+        a(33, "redwood_taiga_hills", new BiomeTaiga(BiomeTaiga.Type.MEGA, (new BiomeBase.a("Mega Taiga Hills")).c(0.45F).d(0.3F).a(0.3F).b(0.8F)));
+        a(34, "extreme_hills_with_trees", new BiomeBigHills(BiomeBigHills.Type.EXTRA_TREES, (new BiomeBase.a("Extreme Hills+")).c(1.0F).d(0.5F).a(0.2F).b(0.3F)));
+        a(35, "savanna", new BiomeSavanna((new BiomeBase.a("Savanna")).c(0.125F).d(0.05F).a(1.2F).b(0.0F).a()));
+        a(36, "savanna_rock", new BiomeSavanna((new BiomeBase.a("Savanna Plateau")).c(1.5F).d(0.025F).a(1.0F).b(0.0F).a()));
+        a(37, "mesa", new BiomeMesa(false, false, (new BiomeBase.a("Mesa")).a(2.0F).b(0.0F).a()));
+        a(38, "mesa_rock", new BiomeMesa(false, true, (new BiomeBase.a("Mesa Plateau F")).c(1.5F).d(0.025F).a(2.0F).b(0.0F).a()));
+        a(39, "mesa_clear_rock", new BiomeMesa(false, false, (new BiomeBase.a("Mesa Plateau")).c(1.5F).d(0.025F).a(2.0F).b(0.0F).a()));
+        a(127, "void", new BiomeVoid((new BiomeBase.a("The Void")).a()));
+        a(129, "mutated_plains", new BiomePlains(true, (new BiomeBase.a("Sunflower Plains")).a("plains").c(0.125F).d(0.05F).a(0.8F).b(0.4F)));
+        a(130, "mutated_desert", new BiomeDesert((new BiomeBase.a("Desert M")).a("desert").c(0.225F).d(0.25F).a(2.0F).b(0.0F).a()));
+        a(131, "mutated_extreme_hills", new BiomeBigHills(BiomeBigHills.Type.MUTATED, (new BiomeBase.a("Extreme Hills M")).a("extreme_hills").c(1.0F).d(0.5F).a(0.2F).b(0.3F)));
+        a(132, "mutated_forest", new BiomeForest(BiomeForest.Type.FLOWER, (new BiomeBase.a("Flower Forest")).a("forest").d(0.4F).a(0.7F).b(0.8F)));
+        a(133, "mutated_taiga", new BiomeTaiga(BiomeTaiga.Type.NORMAL, (new BiomeBase.a("Taiga M")).a("taiga").c(0.3F).d(0.4F).a(0.25F).b(0.8F)));
+        a(134, "mutated_swampland", new BiomeSwamp((new BiomeBase.a("Swampland M")).a("swampland").c(-0.1F).d(0.3F).a(0.8F).b(0.9F).a(14745518)));
+        a(140, "mutated_ice_flats", new BiomeIcePlains(true, (new BiomeBase.a("Ice Plains Spikes")).a("ice_flats").c(0.425F).d(0.45000002F).a(0.0F).b(0.5F).b()));
+        a(149, "mutated_jungle", new BiomeJungle(false, (new BiomeBase.a("Jungle M")).a("jungle").c(0.2F).d(0.4F).a(0.95F).b(0.9F)));
+        a(151, "mutated_jungle_edge", new BiomeJungle(true, (new BiomeBase.a("JungleEdge M")).a("jungle_edge").c(0.2F).d(0.4F).a(0.95F).b(0.8F)));
+        a(155, "mutated_birch_forest", new BiomeForestMutated((new BiomeBase.a("Birch Forest M")).a("birch_forest").c(0.2F).d(0.4F).a(0.6F).b(0.6F)));
+        a(156, "mutated_birch_forest_hills", new BiomeForestMutated((new BiomeBase.a("Birch Forest Hills M")).a("birch_forest").c(0.55F).d(0.5F).a(0.6F).b(0.6F)));
+        a(157, "mutated_roofed_forest", new BiomeForest(BiomeForest.Type.ROOFED, (new BiomeBase.a("Roofed Forest M")).a("roofed_forest").c(0.2F).d(0.4F).a(0.7F).b(0.8F)));
+        a(158, "mutated_taiga_cold", new BiomeTaiga(BiomeTaiga.Type.NORMAL, (new BiomeBase.a("Cold Taiga M")).a("taiga_cold").c(0.3F).d(0.4F).a(-0.5F).b(0.4F).b()));
+        a(160, "mutated_redwood_taiga", new BiomeTaiga(BiomeTaiga.Type.MEGA_SPRUCE, (new BiomeBase.a("Mega Spruce Taiga")).a("redwood_taiga").c(0.2F).d(0.2F).a(0.25F).b(0.8F)));
+        a(161, "mutated_redwood_taiga_hills", new BiomeTaiga(BiomeTaiga.Type.MEGA_SPRUCE, (new BiomeBase.a("Redwood Taiga Hills M")).a("redwood_taiga_hills").c(0.2F).d(0.2F).a(0.25F).b(0.8F)));
+        a(162, "mutated_extreme_hills_with_trees", new BiomeBigHills(BiomeBigHills.Type.MUTATED, (new BiomeBase.a("Extreme Hills+ M")).a("extreme_hills_with_trees").c(1.0F).d(0.5F).a(0.2F).b(0.3F)));
+        a(163, "mutated_savanna", new BiomeSavannaMutated((new BiomeBase.a("Savanna M")).a("savanna").c(0.3625F).d(1.225F).a(1.1F).b(0.0F).a()));
+        a(164, "mutated_savanna_rock", new BiomeSavannaMutated((new BiomeBase.a("Savanna Plateau M")).a("savanna_rock").c(1.05F).d(1.2125001F).a(1.0F).b(0.0F).a()));
+        a(165, "mutated_mesa", new BiomeMesa(true, false, (new BiomeBase.a("Mesa (Bryce)")).a("mesa").a(2.0F).b(0.0F).a()));
+        a(166, "mutated_mesa_rock", new BiomeMesa(false, true, (new BiomeBase.a("Mesa Plateau F M")).a("mesa_rock").c(0.45F).d(0.3F).a(2.0F).b(0.0F).a()));
+        a(167, "mutated_mesa_clear_rock", new BiomeMesa(false, false, (new BiomeBase.a("Mesa Plateau M")).a("mesa_clear_rock").c(0.45F).d(0.3F).a(2.0F).b(0.0F).a()));
+        Collections.addAll(BiomeBase.i, new BiomeBase[] { Biomes.a, Biomes.c, Biomes.d, Biomes.e, Biomes.f, Biomes.g, Biomes.h, Biomes.i, Biomes.m, Biomes.n, Biomes.o, Biomes.p, Biomes.q, Biomes.r, Biomes.s, Biomes.t, Biomes.u, Biomes.w, Biomes.x, Biomes.y, Biomes.z, Biomes.A, Biomes.B, Biomes.C, Biomes.D, Biomes.E, Biomes.F, Biomes.G, Biomes.H, Biomes.I, Biomes.J, Biomes.K, Biomes.L, Biomes.M, Biomes.N, Biomes.O});
+    }
+
+    private static void a(int i, String s, BiomeBase biomebase) {
+        BiomeBase.REGISTRY_ID.a(i, new MinecraftKey(s), biomebase);
+        if (biomebase.b()) {
+            BiomeBase.j.a(biomebase, a((BiomeBase) BiomeBase.REGISTRY_ID.get(new MinecraftKey(biomebase.H))));
+        }
+
+    }
+
+    static class SyntheticClass_1 {
+
+        static final int[] a = new int[EnumCreatureType.values().length];
+
+        static {
+            try {
+                BiomeBase.SyntheticClass_1.a[EnumCreatureType.MONSTER.ordinal()] = 1;
+            } catch (NoSuchFieldError nosuchfielderror) {
+                ;
+            }
+
+            try {
+                BiomeBase.SyntheticClass_1.a[EnumCreatureType.CREATURE.ordinal()] = 2;
+            } catch (NoSuchFieldError nosuchfielderror1) {
+                ;
+            }
+
+            try {
+                BiomeBase.SyntheticClass_1.a[EnumCreatureType.WATER_CREATURE.ordinal()] = 3;
+            } catch (NoSuchFieldError nosuchfielderror2) {
+                ;
+            }
+
+            try {
+                BiomeBase.SyntheticClass_1.a[EnumCreatureType.AMBIENT.ordinal()] = 4;
+            } catch (NoSuchFieldError nosuchfielderror3) {
+                ;
+            }
+
+        }
+    }
+
+    public static class a {
+
+        private final String a;
+        private float b = 0.1F;
+        private float c = 0.2F;
+        private float d = 0.5F;
+        private float e = 0.5F;
+        private int f = 16777215;
+        private boolean g;
+        private boolean h = true;
+        private String i;
+
+        public a(String s) {
+            this.a = s;
+        }
+
+        protected BiomeBase.a a(float f) {
+            if (f > 0.1F && f < 0.2F) {
+                throw new IllegalArgumentException("Please avoid temperatures in the range 0.1 - 0.2 because of snow");
+            } else {
+                this.d = f;
+                return this;
+            }
+        }
+
+        protected BiomeBase.a b(float f) {
+            this.e = f;
+            return this;
+        }
+
+        protected BiomeBase.a c(float f) {
+            this.b = f;
+            return this;
+        }
+
+        protected BiomeBase.a d(float f) {
+            this.c = f;
+            return this;
+        }
+
+        protected BiomeBase.a a() {
+            this.h = false;
+            return this;
+        }
+
+        protected BiomeBase.a b() {
+            this.g = true;
+            return this;
+        }
+
+        protected BiomeBase.a a(int i) {
+            this.f = i;
+            return this;
+        }
+
+        protected BiomeBase.a a(String s) {
+            this.i = s;
+            return this;
+        }
+    }
+
+    public static class BiomeMeta extends WeightedRandom.WeightedRandomChoice {
+
+        public Class<? extends EntityInsentient> b;
+        public int c;
+        public int d;
+
+        public BiomeMeta(Class<? extends EntityInsentient> oclass, int i, int j, int k) {
+            super(i);
+            this.b = oclass;
+            this.c = j;
+            this.d = k;
+        }
+
+        public String toString() {
+            return this.b.getSimpleName() + "*(" + this.c + "-" + this.d + "):" + this.a;
+        }
+    }
+
+    public static enum EnumTemperature {
+
+        OCEAN, COLD, MEDIUM, WARM;
+
+        private EnumTemperature() {}
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BiomeMesa.java b/src/main/java/net/minecraft/server/BiomeMesa.java
new file mode 100644
index 0000000..3ce22aa
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BiomeMesa.java
@@ -0,0 +1,252 @@
+package net.minecraft.server;
+
+import java.util.Arrays;
+import java.util.Random;
+
+public class BiomeMesa extends BiomeBase {
+
+    protected static final IBlockData y = Blocks.DIRT.getBlockData().set(BlockDirt.VARIANT, BlockDirt.EnumDirtVariant.COARSE_DIRT);
+    protected static final IBlockData z = Blocks.GRASS.getBlockData();
+    protected static final IBlockData A = Blocks.HARDENED_CLAY.getBlockData();
+    protected static final IBlockData B = Blocks.STAINED_HARDENED_CLAY.getBlockData();
+    protected static final IBlockData C = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.ORANGE);
+    protected static final IBlockData D = Blocks.SAND.getBlockData().set(BlockSand.VARIANT, BlockSand.EnumSandVariant.RED_SAND);
+    private IBlockData[] E;
+    private long F;
+    private NoiseGenerator3 G;
+    private NoiseGenerator3 H;
+    private NoiseGenerator3 I;
+    private boolean J;
+    private boolean K;
+
+    public BiomeMesa(boolean flag, boolean flag1, BiomeBase.a biomebase_a) {
+        super(biomebase_a);
+        this.J = flag;
+        this.K = flag1;
+        this.v.clear();
+        this.r = BiomeMesa.D;
+        this.s = BiomeMesa.B;
+        this.t.z = -999;
+        this.t.C = 20;
+        this.t.E = 3;
+        this.t.F = 5;
+        this.t.A = 0;
+        this.v.clear();
+        if (flag1) {
+            this.t.z = 5;
+        }
+
+    }
+
+    public WorldGenTreeAbstract a(Random random) {
+        return BiomeMesa.n;
+    }
+
+    public void a(World world, Random random, BlockPosition blockposition) {
+        super.a(world, random, blockposition);
+    }
+
+    public void a(World world, Random random, ChunkSnapshot chunksnapshot, int i, int j, double d0) {
+        if (this.E == null || this.F != world.getSeed()) {
+            this.a(world.getSeed());
+        }
+
+        if (this.G == null || this.H == null || this.F != world.getSeed()) {
+            Random random1 = new Random(this.F);
+
+            this.G = new NoiseGenerator3(random1, 4);
+            this.H = new NoiseGenerator3(random1, 1);
+        }
+
+        this.F = world.getSeed();
+        double d1 = 0.0D;
+        int k;
+        int l;
+
+        if (this.J) {
+            k = (i & -16) + (j & 15);
+            l = (j & -16) + (i & 15);
+            double d2 = Math.min(Math.abs(d0), this.G.a((double) k * 0.25D, (double) l * 0.25D));
+
+            if (d2 > 0.0D) {
+                double d3 = 0.001953125D;
+                double d4 = Math.abs(this.H.a((double) k * d3, (double) l * d3));
+
+                d1 = d2 * d2 * 2.5D;
+                double d5 = Math.ceil(d4 * 50.0D) + 14.0D;
+
+                if (d1 > d5) {
+                    d1 = d5;
+                }
+
+                d1 += 64.0D;
+            }
+        }
+
+        k = i & 15;
+        l = j & 15;
+        int i1 = world.K();
+        IBlockData iblockdata = BiomeMesa.B;
+        IBlockData iblockdata1 = this.s;
+        int j1 = (int) (d0 / 3.0D + 3.0D + random.nextDouble() * 0.25D);
+        boolean flag = Math.cos(d0 / 3.0D * 3.141592653589793D) > 0.0D;
+        int k1 = -1;
+        boolean flag1 = false;
+
+        for (int l1 = 255; l1 >= 0; --l1) {
+            if (chunksnapshot.a(l, l1, k).getMaterial() == Material.AIR && l1 < (int) d1) {
+                chunksnapshot.a(l, l1, k, BiomeMesa.a);
+            }
+
+            if (l1 <= random.nextInt(5)) {
+                chunksnapshot.a(l, l1, k, BiomeMesa.c);
+            } else {
+                IBlockData iblockdata2 = chunksnapshot.a(l, l1, k);
+
+                if (iblockdata2.getMaterial() == Material.AIR) {
+                    k1 = -1;
+                } else if (iblockdata2.getBlock() == Blocks.STONE) {
+                    if (k1 == -1) {
+                        flag1 = false;
+                        if (j1 <= 0) {
+                            iblockdata = BiomeMesa.b;
+                            iblockdata1 = BiomeMesa.a;
+                        } else if (l1 >= i1 - 4 && l1 <= i1 + 1) {
+                            iblockdata = BiomeMesa.B;
+                            iblockdata1 = this.s;
+                        }
+
+                        if (l1 < i1 && (iblockdata == null || iblockdata.getMaterial() == Material.AIR)) {
+                            iblockdata = BiomeMesa.h;
+                        }
+
+                        k1 = j1 + Math.max(0, l1 - i1);
+                        if (l1 >= i1 - 1) {
+                            if (this.K && l1 > 86 + j1 * 2) {
+                                if (flag) {
+                                    chunksnapshot.a(l, l1, k, BiomeMesa.y);
+                                } else {
+                                    chunksnapshot.a(l, l1, k, BiomeMesa.z);
+                                }
+                            } else if (l1 > i1 + 3 + j1) {
+                                IBlockData iblockdata3;
+
+                                if (l1 >= 64 && l1 <= 127) {
+                                    if (flag) {
+                                        iblockdata3 = BiomeMesa.A;
+                                    } else {
+                                        iblockdata3 = this.a(i, l1, j);
+                                    }
+                                } else {
+                                    iblockdata3 = BiomeMesa.C;
+                                }
+
+                                chunksnapshot.a(l, l1, k, iblockdata3);
+                            } else {
+                                chunksnapshot.a(l, l1, k, this.r);
+                                flag1 = true;
+                            }
+                        } else {
+                            chunksnapshot.a(l, l1, k, iblockdata1);
+                            if (iblockdata1.getBlock() == Blocks.STAINED_HARDENED_CLAY) {
+                                chunksnapshot.a(l, l1, k, BiomeMesa.C);
+                            }
+                        }
+                    } else if (k1 > 0) {
+                        --k1;
+                        if (flag1) {
+                            chunksnapshot.a(l, l1, k, BiomeMesa.C);
+                        } else {
+                            chunksnapshot.a(l, l1, k, this.a(i, l1, j));
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    private void a(long i) {
+        this.E = new IBlockData[64];
+        Arrays.fill(this.E, BiomeMesa.A);
+        Random random = new Random(i);
+
+        this.I = new NoiseGenerator3(random, 1);
+
+        int j;
+
+        for (j = 0; j < 64; ++j) {
+            j += random.nextInt(5) + 1;
+            if (j < 64) {
+                this.E[j] = BiomeMesa.C;
+            }
+        }
+
+        j = random.nextInt(4) + 2;
+
+        int k;
+        int l;
+        int i1;
+        int j1;
+
+        for (k = 0; k < j; ++k) {
+            l = random.nextInt(3) + 1;
+            i1 = random.nextInt(64);
+
+            for (j1 = 0; i1 + j1 < 64 && j1 < l; ++j1) {
+                this.E[i1 + j1] = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.YELLOW);
+            }
+        }
+
+        k = random.nextInt(4) + 2;
+
+        int k1;
+
+        for (l = 0; l < k; ++l) {
+            i1 = random.nextInt(3) + 2;
+            j1 = random.nextInt(64);
+
+            for (k1 = 0; j1 + k1 < 64 && k1 < i1; ++k1) {
+                this.E[j1 + k1] = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.BROWN);
+            }
+        }
+
+        l = random.nextInt(4) + 2;
+
+        for (i1 = 0; i1 < l; ++i1) {
+            j1 = random.nextInt(3) + 1;
+            k1 = random.nextInt(64);
+
+            for (int l1 = 0; k1 + l1 < 64 && l1 < j1; ++l1) {
+                this.E[k1 + l1] = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.RED);
+            }
+        }
+
+        i1 = random.nextInt(3) + 3;
+        j1 = 0;
+
+        for (k1 = 0; k1 < i1; ++k1) {
+            byte b0 = 1;
+
+            j1 += random.nextInt(16) + 4;
+
+            for (int i2 = 0; j1 + i2 < 64 && i2 < b0; ++i2) {
+                this.E[j1 + i2] = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.WHITE);
+                if (j1 + i2 > 1 && random.nextBoolean()) {
+                    this.E[j1 + i2 - 1] = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.SILVER);
+                }
+
+                if (j1 + i2 < 63 && random.nextBoolean()) {
+                    this.E[j1 + i2 + 1] = BiomeMesa.B.set(BlockCloth.COLOR, EnumColor.SILVER);
+                }
+            }
+        }
+
+    }
+
+    private IBlockData a(int i, int j, int k) {
+        int l = (int) Math.round(this.I.a((double) i / 512.0D, (double) i / 512.0D) * 2.0D);
+
+        return this.E[(j + l + 64) % 64];
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BlockChest.java b/src/main/java/net/minecraft/server/BlockChest.java
new file mode 100644
index 0000000..7d27317
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BlockChest.java
@@ -0,0 +1,452 @@
+package net.minecraft.server;
+
+import java.util.Iterator;
+
+public class BlockChest extends BlockTileEntity {
+
+    public static final BlockStateDirection FACING = BlockFacingHorizontal.FACING;
+    protected static final AxisAlignedBB b = new AxisAlignedBB(0.0625D, 0.0D, 0.0D, 0.9375D, 0.875D, 0.9375D);
+    protected static final AxisAlignedBB c = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 0.875D, 1.0D);
+    protected static final AxisAlignedBB d = new AxisAlignedBB(0.0D, 0.0D, 0.0625D, 0.9375D, 0.875D, 0.9375D);
+    protected static final AxisAlignedBB e = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 1.0D, 0.875D, 0.9375D);
+    protected static final AxisAlignedBB f = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 0.875D, 0.9375D);
+    public final Type g;
+
+    protected BlockChest(Type blockchest_type) {
+        super(Material.WOOD);
+        this.w(this.blockStateList.getBlockData().set(BlockChest.FACING, EnumDirection.NORTH));
+        this.g = blockchest_type;
+        this.a(blockchest_type == Type.TRAP ? CreativeModeTab.d : CreativeModeTab.c);
+    }
+
+    public boolean b(IBlockData iblockdata) {
+        return false;
+    }
+
+    public boolean c(IBlockData iblockdata) {
+        return false;
+    }
+
+    public EnumRenderType a(IBlockData iblockdata) {
+        return EnumRenderType.ENTITYBLOCK_ANIMATED;
+    }
+
+    public AxisAlignedBB a(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
+        return iblockaccess.getType(blockposition.north()).getBlock() == this ? BlockChest.b : (iblockaccess.getType(blockposition.south()).getBlock() == this ? BlockChest.c : (iblockaccess.getType(blockposition.west()).getBlock() == this ? BlockChest.d : (iblockaccess.getType(blockposition.east()).getBlock() == this ? BlockChest.e : BlockChest.f)));
+    }
+
+    public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        this.e(world, blockposition, iblockdata);
+        Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
+
+        while (iterator.hasNext()) {
+            EnumDirection enumdirection = (EnumDirection) iterator.next();
+            BlockPosition blockposition1 = blockposition.shift(enumdirection);
+            IBlockData iblockdata1 = world.getType(blockposition1);
+
+            if (iblockdata1.getBlock() == this) {
+                this.e(world, blockposition1, iblockdata1);
+            }
+        }
+
+    }
+
+    public IBlockData getPlacedState(World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2, int i, EntityLiving entityliving) {
+        return this.getBlockData().set(BlockChest.FACING, entityliving.getDirection());
+    }
+
+    public void postPlace(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving, ItemStack itemstack) {
+        EnumDirection enumdirection = EnumDirection.fromType2(MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3).opposite();
+
+        iblockdata = iblockdata.set(BlockChest.FACING, enumdirection);
+        BlockPosition blockposition1 = blockposition.north();
+        BlockPosition blockposition2 = blockposition.south();
+        BlockPosition blockposition3 = blockposition.west();
+        BlockPosition blockposition4 = blockposition.east();
+        boolean flag = this == world.getType(blockposition1).getBlock();
+        boolean flag1 = this == world.getType(blockposition2).getBlock();
+        boolean flag2 = this == world.getType(blockposition3).getBlock();
+        boolean flag3 = this == world.getType(blockposition4).getBlock();
+
+        if (!flag && !flag1 && !flag2 && !flag3) {
+            world.setTypeAndData(blockposition, iblockdata, 3);
+        } else if (enumdirection.k() == EnumDirection.EnumAxis.X && (flag || flag1)) {
+            if (flag) {
+                world.setTypeAndData(blockposition1, iblockdata, 3);
+            } else {
+                world.setTypeAndData(blockposition2, iblockdata, 3);
+            }
+
+            world.setTypeAndData(blockposition, iblockdata, 3);
+        } else if (enumdirection.k() == EnumDirection.EnumAxis.Z && (flag2 || flag3)) {
+            if (flag2) {
+                world.setTypeAndData(blockposition3, iblockdata, 3);
+            } else {
+                world.setTypeAndData(blockposition4, iblockdata, 3);
+            }
+
+            world.setTypeAndData(blockposition, iblockdata, 3);
+        }
+
+        if (itemstack.hasName()) {
+            TileEntity tileentity = world.getTileEntity(blockposition);
+
+            if (tileentity instanceof TileEntityChest) {
+                ((TileEntityChest) tileentity).a(itemstack.getName());
+            }
+        }
+
+    }
+
+    public IBlockData e(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        if (world.isClientSide) {
+            return iblockdata;
+        } else {
+            IBlockData iblockdata1 = world.getType(blockposition.north());
+            IBlockData iblockdata2 = world.getType(blockposition.south());
+            IBlockData iblockdata3 = world.getType(blockposition.west());
+            IBlockData iblockdata4 = world.getType(blockposition.east());
+            EnumDirection enumdirection = (EnumDirection) iblockdata.get(BlockChest.FACING);
+
+            if (iblockdata1.getBlock() != this && iblockdata2.getBlock() != this) {
+                boolean flag = iblockdata1.b();
+                boolean flag1 = iblockdata2.b();
+
+                if (iblockdata3.getBlock() == this || iblockdata4.getBlock() == this) {
+                    BlockPosition blockposition1 = iblockdata3.getBlock() == this ? blockposition.west() : blockposition.east();
+                    IBlockData iblockdata5 = world.getType(blockposition1.north());
+                    IBlockData iblockdata6 = world.getType(blockposition1.south());
+
+                    enumdirection = EnumDirection.SOUTH;
+                    EnumDirection enumdirection1;
+
+                    if (iblockdata3.getBlock() == this) {
+                        enumdirection1 = (EnumDirection) iblockdata3.get(BlockChest.FACING);
+                    } else {
+                        enumdirection1 = (EnumDirection) iblockdata4.get(BlockChest.FACING);
+                    }
+
+                    if (enumdirection1 == EnumDirection.NORTH) {
+                        enumdirection = EnumDirection.NORTH;
+                    }
+
+                    if ((flag || iblockdata5.b()) && !flag1 && !iblockdata6.b()) {
+                        enumdirection = EnumDirection.SOUTH;
+                    }
+
+                    if ((flag1 || iblockdata6.b()) && !flag && !iblockdata5.b()) {
+                        enumdirection = EnumDirection.NORTH;
+                    }
+                }
+            } else {
+                BlockPosition blockposition2 = iblockdata1.getBlock() == this ? blockposition.north() : blockposition.south();
+                IBlockData iblockdata7 = world.getType(blockposition2.west());
+                IBlockData iblockdata8 = world.getType(blockposition2.east());
+
+                enumdirection = EnumDirection.EAST;
+                EnumDirection enumdirection2;
+
+                if (iblockdata1.getBlock() == this) {
+                    enumdirection2 = (EnumDirection) iblockdata1.get(BlockChest.FACING);
+                } else {
+                    enumdirection2 = (EnumDirection) iblockdata2.get(BlockChest.FACING);
+                }
+
+                if (enumdirection2 == EnumDirection.WEST) {
+                    enumdirection = EnumDirection.WEST;
+                }
+
+                if ((iblockdata3.b() || iblockdata7.b()) && !iblockdata4.b() && !iblockdata8.b()) {
+                    enumdirection = EnumDirection.EAST;
+                }
+
+                if ((iblockdata4.b() || iblockdata8.b()) && !iblockdata3.b() && !iblockdata7.b()) {
+                    enumdirection = EnumDirection.WEST;
+                }
+            }
+
+            iblockdata = iblockdata.set(BlockChest.FACING, enumdirection);
+            world.setTypeAndData(blockposition, iblockdata, 3);
+            return iblockdata;
+        }
+    }
+
+    public IBlockData f(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        EnumDirection enumdirection = null;
+        Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
+
+        while (iterator.hasNext()) {
+            EnumDirection enumdirection1 = (EnumDirection) iterator.next();
+            IBlockData iblockdata1 = world.getType(blockposition.shift(enumdirection1));
+
+            if (iblockdata1.getBlock() == this) {
+                return iblockdata;
+            }
+
+            if (iblockdata1.b()) {
+                if (enumdirection != null) {
+                    enumdirection = null;
+                    break;
+                }
+
+                enumdirection = enumdirection1;
+            }
+        }
+
+        if (enumdirection != null) {
+            return iblockdata.set(BlockChest.FACING, enumdirection.opposite());
+        } else {
+            EnumDirection enumdirection2 = (EnumDirection) iblockdata.get(BlockChest.FACING);
+
+            if (world.getType(blockposition.shift(enumdirection2)).b()) {
+                enumdirection2 = enumdirection2.opposite();
+            }
+
+            if (world.getType(blockposition.shift(enumdirection2)).b()) {
+                enumdirection2 = enumdirection2.e();
+            }
+
+            if (world.getType(blockposition.shift(enumdirection2)).b()) {
+                enumdirection2 = enumdirection2.opposite();
+            }
+
+            return iblockdata.set(BlockChest.FACING, enumdirection2);
+        }
+    }
+
+    public boolean canPlace(World world, BlockPosition blockposition) {
+        int i = 0;
+        BlockPosition blockposition1 = blockposition.west();
+        BlockPosition blockposition2 = blockposition.east();
+        BlockPosition blockposition3 = blockposition.north();
+        BlockPosition blockposition4 = blockposition.south();
+
+        if (world.getType(blockposition1).getBlock() == this) {
+            if (this.d(world, blockposition1)) {
+                return false;
+            }
+
+            ++i;
+        }
+
+        if (world.getType(blockposition2).getBlock() == this) {
+            if (this.d(world, blockposition2)) {
+                return false;
+            }
+
+            ++i;
+        }
+
+        if (world.getType(blockposition3).getBlock() == this) {
+            if (this.d(world, blockposition3)) {
+                return false;
+            }
+
+            ++i;
+        }
+
+        if (world.getType(blockposition4).getBlock() == this) {
+            if (this.d(world, blockposition4)) {
+                return false;
+            }
+
+            ++i;
+        }
+
+        return i <= 1;
+    }
+
+    private boolean d(World world, BlockPosition blockposition) {
+        if (world.getType(blockposition).getBlock() != this) {
+            return false;
+        } else {
+            Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
+
+            EnumDirection enumdirection;
+
+            do {
+                if (!iterator.hasNext()) {
+                    return false;
+                }
+
+                enumdirection = (EnumDirection) iterator.next();
+            } while (world.getType(blockposition.shift(enumdirection)).getBlock() != this);
+
+            return true;
+        }
+    }
+
+    public void doPhysics(World world, BlockPosition blockposition, IBlockData iblockdata, Block block) {
+        super.doPhysics(world, blockposition, iblockdata, block);
+        TileEntity tileentity = world.getTileEntity(blockposition);
+
+        if (tileentity instanceof TileEntityChest) {
+            tileentity.invalidateBlockCache();
+        }
+
+    }
+
+    public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        TileEntity tileentity = world.getTileEntity(blockposition);
+
+        if (tileentity instanceof IInventory) {
+            InventoryUtils.dropInventory(world, blockposition, (IInventory) tileentity);
+            world.updateAdjacentComparators(blockposition, this);
+        }
+
+        super.remove(world, blockposition, iblockdata);
+    }
+
+    public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, ItemStack itemstack, EnumDirection enumdirection, float f, float f1, float f2) {
+        if (world.isClientSide) {
+            return true;
+        } else {
+            ITileInventory itileinventory = this.c(world, blockposition);
+
+            if (itileinventory != null) {
+                entityhuman.openContainer(itileinventory);
+                if (this.g == Type.BASIC) {
+                    entityhuman.b(StatisticList.ac);
+                } else if (this.g == Type.TRAP) {
+                    entityhuman.b(StatisticList.W);
+                }
+            }
+
+            return true;
+        }
+    }
+
+    public ITileInventory c(World world, BlockPosition blockposition) {
+        TileEntity tileentity = world.getTileEntity(blockposition);
+
+        if (!(tileentity instanceof TileEntityChest)) {
+            return null;
+        } else {
+            Object object = (TileEntityChest) tileentity;
+
+            if (this.e(world, blockposition)) {
+                return null;
+            } else {
+                Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
+
+                while (iterator.hasNext()) {
+                    EnumDirection enumdirection = (EnumDirection) iterator.next();
+                    BlockPosition blockposition1 = blockposition.shift(enumdirection);
+                    Block block = world.getType(blockposition1).getBlock();
+
+                    if (block == this) {
+                        if (this.e(world, blockposition1)) {
+                            return null;
+                        }
+
+                        TileEntity tileentity1 = world.getTileEntity(blockposition1);
+
+                        if (tileentity1 instanceof TileEntityChest) {
+                            if (enumdirection != EnumDirection.WEST && enumdirection != EnumDirection.NORTH) {
+                                object = new InventoryLargeChest("container.chestDouble", (ITileInventory) object, (TileEntityChest) tileentity1);
+                            } else {
+                                object = new InventoryLargeChest("container.chestDouble", (TileEntityChest) tileentity1, (ITileInventory) object);
+                            }
+                        }
+                    }
+                }
+
+                return (ITileInventory) object;
+            }
+        }
+    }
+
+    public TileEntity a(World world, int i) {
+        return new TileEntityChest();
+    }
+
+    public boolean isPowerSource(IBlockData iblockdata) {
+        return this.g == Type.TRAP;
+    }
+
+    public int b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+        if (!iblockdata.m()) {
+            return 0;
+        } else {
+            int i = 0;
+            TileEntity tileentity = iblockaccess.getTileEntity(blockposition);
+
+            if (tileentity instanceof TileEntityChest) {
+                i = ((TileEntityChest) tileentity).l;
+            }
+
+            return MathHelper.clamp(i, 0, 15);
+        }
+    }
+
+    public int c(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+        return enumdirection == EnumDirection.UP ? iblockdata.a(iblockaccess, blockposition, enumdirection) : 0;
+    }
+
+    private boolean e(World world, BlockPosition blockposition) {
+        return this.i(world, blockposition) || this.j(world, blockposition);
+    }
+
+    private boolean i(World world, BlockPosition blockposition) {
+        return world.getType(blockposition.up()).l();
+    }
+
+    private boolean j(World world, BlockPosition blockposition) {
+        Iterator iterator = world.a(EntityOcelot.class, new AxisAlignedBB((double) blockposition.getX(), (double) (blockposition.getY() + 1), (double) blockposition.getZ(), (double) (blockposition.getX() + 1), (double) (blockposition.getY() + 2), (double) (blockposition.getZ() + 1))).iterator();
+
+        EntityOcelot entityocelot;
+
+        do {
+            if (!iterator.hasNext()) {
+                return false;
+            }
+
+            Entity entity = (Entity) iterator.next();
+
+            entityocelot = (EntityOcelot) entity;
+        } while (!entityocelot.isSitting());
+
+        return true;
+    }
+
+    public boolean isComplexRedstone(IBlockData iblockdata) {
+        return true;
+    }
+
+    public int d(IBlockData iblockdata, World world, BlockPosition blockposition) {
+        return Container.b((IInventory) this.c(world, blockposition));
+    }
+
+    public IBlockData fromLegacyData(int i) {
+        EnumDirection enumdirection = EnumDirection.fromType1(i);
+
+        if (enumdirection.k() == EnumDirection.EnumAxis.Y) {
+            enumdirection = EnumDirection.NORTH;
+        }
+
+        return this.getBlockData().set(BlockChest.FACING, enumdirection);
+    }
+
+    public int toLegacyData(IBlockData iblockdata) {
+        return ((EnumDirection) iblockdata.get(BlockChest.FACING)).a();
+    }
+
+    public IBlockData a(IBlockData iblockdata, EnumBlockRotation enumblockrotation) {
+        return iblockdata.set(BlockChest.FACING, enumblockrotation.a((EnumDirection) iblockdata.get(BlockChest.FACING)));
+    }
+
+    public IBlockData a(IBlockData iblockdata, EnumBlockMirror enumblockmirror) {
+        return iblockdata.a(enumblockmirror.a((EnumDirection) iblockdata.get(BlockChest.FACING)));
+    }
+
+    protected BlockStateList getStateList() {
+        return new BlockStateList(this, new IBlockState[] { BlockChest.FACING});
+    }
+
+    public static enum Type {
+
+        BASIC, TRAP;
+
+        private Type() {}
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BlockFalling.java b/src/main/java/net/minecraft/server/BlockFalling.java
new file mode 100644
index 0000000..6654240
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BlockFalling.java
@@ -0,0 +1,75 @@
+package net.minecraft.server;
+
+import java.util.Random;
+
+public class BlockFalling extends Block {
+
+    public static boolean instaFall;
+
+    public BlockFalling() {
+        super(Material.SAND);
+        this.a(CreativeModeTab.b);
+    }
+
+    public BlockFalling(Material material) {
+        super(material);
+    }
+
+    public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        world.a(blockposition, (Block) this, this.a(world));
+    }
+
+    public void doPhysics(World world, BlockPosition blockposition, IBlockData iblockdata, Block block) {
+        world.a(blockposition, (Block) this, this.a(world));
+    }
+
+    public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) {
+        if (!world.isClientSide) {
+            this.b(world, blockposition);
+        }
+
+    }
+
+    private void b(World world, BlockPosition blockposition) {
+        if (i(world.getType(blockposition.down())) && blockposition.getY() >= 0) {
+            byte b0 = 32;
+
+            if (!BlockFalling.instaFall && world.areChunksLoadedBetween(blockposition.a(-b0, -b0, -b0), blockposition.a(b0, b0, b0))) {
+                if (!world.isClientSide) {
+                    EntityFallingBlock entityfallingblock = new EntityFallingBlock(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, world.getType(blockposition));
+
+                    this.a(entityfallingblock);
+                    world.addEntity(entityfallingblock);
+                }
+            } else {
+                world.setAir(blockposition);
+
+                BlockPosition blockposition1;
+
+                for (blockposition1 = blockposition.down(); i(world.getType(blockposition1)) && blockposition1.getY() > 0; blockposition1 = blockposition1.down()) {
+                    ;
+                }
+
+                if (blockposition1.getY() > 0) {
+                    world.setTypeUpdate(blockposition1.up(), this.getBlockData());
+                }
+            }
+
+        }
+    }
+
+    protected void a(EntityFallingBlock entityfallingblock) {}
+
+    public int a(World world) {
+        return 2;
+    }
+
+    public static boolean i(IBlockData iblockdata) {
+        Block block = iblockdata.getBlock();
+        Material material = iblockdata.getMaterial();
+
+        return block == Blocks.FIRE || material == Material.AIR || material == Material.WATER || material == Material.LAVA;
+    }
+
+    public void a_(World world, BlockPosition blockposition) {}
+}
diff --git a/src/main/java/net/minecraft/server/BlockFluids.java b/src/main/java/net/minecraft/server/BlockFluids.java
new file mode 100644
index 0000000..675cdc0
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BlockFluids.java
@@ -0,0 +1,224 @@
+package net.minecraft.server;
+
+import java.util.Iterator;
+import java.util.Random;
+
+public abstract class BlockFluids extends Block {
+
+    public static final BlockStateInteger LEVEL = BlockStateInteger.of("level", 0, 15);
+
+    protected BlockFluids(Material material) {
+        super(material);
+        this.w(this.blockStateList.getBlockData().set(BlockFluids.LEVEL, Integer.valueOf(0)));
+        this.a(true);
+    }
+
+    public AxisAlignedBB a(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
+        return BlockFluids.j;
+    }
+
+    public AxisAlignedBB a(IBlockData iblockdata, World world, BlockPosition blockposition) {
+        return BlockFluids.k;
+    }
+
+    public boolean b(IBlockAccess iblockaccess, BlockPosition blockposition) {
+        return this.material != Material.LAVA;
+    }
+
+    public static float e(int i) {
+        if (i >= 8) {
+            i = 0;
+        }
+
+        return (float) (i + 1) / 9.0F;
+    }
+
+    protected int c(IBlockAccess iblockaccess, BlockPosition blockposition) {
+        return iblockaccess.getType(blockposition).getMaterial() == this.material ? ((Integer) iblockaccess.getType(blockposition).get(BlockFluids.LEVEL)).intValue() : -1;
+    }
+
+    protected int d(IBlockAccess iblockaccess, BlockPosition blockposition) {
+        int i = this.c(iblockaccess, blockposition);
+
+        return i >= 8 ? 0 : i;
+    }
+
+    public boolean c(IBlockData iblockdata) {
+        return false;
+    }
+
+    public boolean b(IBlockData iblockdata) {
+        return false;
+    }
+
+    public boolean a(IBlockData iblockdata, boolean flag) {
+        return flag && ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue() == 0;
+    }
+
+    public boolean a(IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+        Material material = iblockaccess.getType(blockposition).getMaterial();
+
+        return material == this.material ? false : (enumdirection == EnumDirection.UP ? true : (material == Material.ICE ? false : super.a(iblockaccess, blockposition, enumdirection)));
+    }
+
+    public EnumRenderType a(IBlockData iblockdata) {
+        return EnumRenderType.LIQUID;
+    }
+
+    public Item getDropType(IBlockData iblockdata, Random random, int i) {
+        return null;
+    }
+
+    public int a(Random random) {
+        return 0;
+    }
+
+    protected Vec3D f(IBlockAccess iblockaccess, BlockPosition blockposition) {
+        double d0 = 0.0D;
+        double d1 = 0.0D;
+        double d2 = 0.0D;
+        int i = this.d(iblockaccess, blockposition);
+        BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
+        Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
+
+        while (iterator.hasNext()) {
+            EnumDirection enumdirection = (EnumDirection) iterator.next();
+
+            blockposition_pooledblockposition.h(blockposition).c(enumdirection);
+            int j = this.d(iblockaccess, blockposition_pooledblockposition);
+            int k;
+
+            if (j < 0) {
+                if (!iblockaccess.getType(blockposition_pooledblockposition).getMaterial().isSolid()) {
+                    j = this.d(iblockaccess, blockposition_pooledblockposition.down());
+                    if (j >= 0) {
+                        k = j - (i - 8);
+                        d0 += (double) (enumdirection.getAdjacentX() * k);
+                        d1 += (double) (enumdirection.getAdjacentY() * k);
+                        d2 += (double) (enumdirection.getAdjacentZ() * k);
+                    }
+                }
+            } else if (j >= 0) {
+                k = j - i;
+                d0 += (double) (enumdirection.getAdjacentX() * k);
+                d1 += (double) (enumdirection.getAdjacentY() * k);
+                d2 += (double) (enumdirection.getAdjacentZ() * k);
+            }
+        }
+
+        Vec3D vec3d = new Vec3D(d0, d1, d2);
+
+        if (((Integer) iblockaccess.getType(blockposition).get(BlockFluids.LEVEL)).intValue() >= 8) {
+            Iterator iterator1 = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
+
+            while (iterator1.hasNext()) {
+                EnumDirection enumdirection1 = (EnumDirection) iterator1.next();
+
+                blockposition_pooledblockposition.h(blockposition).c(enumdirection1);
+                if (this.a(iblockaccess, (BlockPosition) blockposition_pooledblockposition, enumdirection1) || this.a(iblockaccess, blockposition_pooledblockposition.up(), enumdirection1)) {
+                    vec3d = vec3d.a().add(0.0D, -6.0D, 0.0D);
+                    break;
+                }
+            }
+        }
+
+        blockposition_pooledblockposition.t();
+        return vec3d.a();
+    }
+
+    public Vec3D a(World world, BlockPosition blockposition, Entity entity, Vec3D vec3d) {
+        return vec3d.e(this.f(world, blockposition));
+    }
+
+    public int a(World world) {
+        return this.material == Material.WATER ? 5 : (this.material == Material.LAVA ? (world.worldProvider.m() ? 10 : 30) : 0);
+    }
+
+    public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        this.e(world, blockposition, iblockdata);
+    }
+
+    public void doPhysics(World world, BlockPosition blockposition, IBlockData iblockdata, Block block) {
+        this.e(world, blockposition, iblockdata);
+    }
+
+    public boolean e(World world, BlockPosition blockposition, IBlockData iblockdata) {
+        if (this.material == Material.LAVA) {
+            boolean flag = false;
+            EnumDirection[] aenumdirection = EnumDirection.values();
+            int i = aenumdirection.length;
+
+            for (int j = 0; j < i; ++j) {
+                EnumDirection enumdirection = aenumdirection[j];
+
+                if (enumdirection != EnumDirection.DOWN && world.getType(blockposition.shift(enumdirection)).getMaterial() == Material.WATER) {
+                    flag = true;
+                    break;
+                }
+            }
+
+            if (flag) {
+                Integer integer = (Integer) iblockdata.get(BlockFluids.LEVEL);
+
+                if (integer.intValue() == 0) {
+                    world.setTypeUpdate(blockposition, Blocks.OBSIDIAN.getBlockData());
+                    this.fizz(world, blockposition);
+                    return true;
+                }
+
+                if (integer.intValue() <= 4) {
+                    world.setTypeUpdate(blockposition, Blocks.COBBLESTONE.getBlockData());
+                    this.fizz(world, blockposition);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    protected void fizz(World world, BlockPosition blockposition) {
+        double d0 = (double) blockposition.getX();
+        double d1 = (double) blockposition.getY();
+        double d2 = (double) blockposition.getZ();
+
+        world.a((EntityHuman) null, blockposition, SoundEffects.db, SoundCategory.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
+
+        for (int i = 0; i < 8; ++i) {
+            world.addParticle(EnumParticle.SMOKE_LARGE, d0 + Math.random(), d1 + 1.2D, d2 + Math.random(), 0.0D, 0.0D, 0.0D, new int[0]);
+        }
+
+    }
+
+    public IBlockData fromLegacyData(int i) {
+        return this.getBlockData().set(BlockFluids.LEVEL, Integer.valueOf(i));
+    }
+
+    public int toLegacyData(IBlockData iblockdata) {
+        return ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue();
+    }
+
+    protected BlockStateList getStateList() {
+        return new BlockStateList(this, new IBlockState[] { BlockFluids.LEVEL});
+    }
+
+    public static BlockFlowing a(Material material) {
+        if (material == Material.WATER) {
+            return Blocks.FLOWING_WATER;
+        } else if (material == Material.LAVA) {
+            return Blocks.FLOWING_LAVA;
+        } else {
+            throw new IllegalArgumentException("Invalid material");
+        }
+    }
+
+    public static BlockStationary b(Material material) {
+        if (material == Material.WATER) {
+            return Blocks.WATER;
+        } else if (material == Material.LAVA) {
+            return Blocks.LAVA;
+        } else {
+            throw new IllegalArgumentException("Invalid material");
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
new file mode 100644
index 0000000..e7a95f3
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
@@ -0,0 +1,381 @@
+package net.minecraft.server;
+
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Lists;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class BlockPosition extends BaseBlockPosition {
+
+    private static final Logger c = LogManager.getLogger();
+    public static final BlockPosition ZERO = new BlockPosition(0, 0, 0);
+    private static final int d = 1 + MathHelper.e(MathHelper.c(30000000));
+    private static final int e = BlockPosition.d;
+    private static final int f = 64 - BlockPosition.d - BlockPosition.e;
+    private static final int g = 0 + BlockPosition.e;
+    private static final int h = BlockPosition.g + BlockPosition.f;
+    private static final long i = (1L << BlockPosition.d) - 1L;
+    private static final long j = (1L << BlockPosition.f) - 1L;
+    private static final long k = (1L << BlockPosition.e) - 1L;
+
+    public BlockPosition(int i, int j, int k) {
+        super(i, j, k);
+    }
+
+    public BlockPosition(double d0, double d1, double d2) {
+        super(d0, d1, d2);
+    }
+
+    public BlockPosition(Entity entity) {
+        this(entity.locX, entity.locY, entity.locZ);
+    }
+
+    public BlockPosition(Vec3D vec3d) {
+        this(vec3d.x, vec3d.y, vec3d.z);
+    }
+
+    public BlockPosition(BaseBlockPosition baseblockposition) {
+        this(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ());
+    }
+
+    public BlockPosition a(double d0, double d1, double d2) {
+        return d0 == 0.0D && d1 == 0.0D && d2 == 0.0D ? this : new BlockPosition((double) this.getX() + d0, (double) this.getY() + d1, (double) this.getZ() + d2);
+    }
+
+    public BlockPosition a(int i, int j, int k) {
+        return i == 0 && j == 0 && k == 0 ? this : new BlockPosition(this.getX() + i, this.getY() + j, this.getZ() + k);
+    }
+
+    public BlockPosition a(BaseBlockPosition baseblockposition) {
+        return baseblockposition.getX() == 0 && baseblockposition.getY() == 0 && baseblockposition.getZ() == 0 ? this : new BlockPosition(this.getX() + baseblockposition.getX(), this.getY() + baseblockposition.getY(), this.getZ() + baseblockposition.getZ());
+    }
+
+    public BlockPosition b(BaseBlockPosition baseblockposition) {
+        return baseblockposition.getX() == 0 && baseblockposition.getY() == 0 && baseblockposition.getZ() == 0 ? this : new BlockPosition(this.getX() - baseblockposition.getX(), this.getY() - baseblockposition.getY(), this.getZ() - baseblockposition.getZ());
+    }
+
+    public BlockPosition up() {
+        return this.up(1);
+    }
+
+    public BlockPosition up(int i) {
+        return this.shift(EnumDirection.UP, i);
+    }
+
+    public BlockPosition down() {
+        return this.down(1);
+    }
+
+    public BlockPosition down(int i) {
+        return this.shift(EnumDirection.DOWN, i);
+    }
+
+    public BlockPosition north() {
+        return this.north(1);
+    }
+
+    public BlockPosition north(int i) {
+        return this.shift(EnumDirection.NORTH, i);
+    }
+
+    public BlockPosition south() {
+        return this.south(1);
+    }
+
+    public BlockPosition south(int i) {
+        return this.shift(EnumDirection.SOUTH, i);
+    }
+
+    public BlockPosition west() {
+        return this.west(1);
+    }
+
+    public BlockPosition west(int i) {
+        return this.shift(EnumDirection.WEST, i);
+    }
+
+    public BlockPosition east() {
+        return this.east(1);
+    }
+
+    public BlockPosition east(int i) {
+        return this.shift(EnumDirection.EAST, i);
+    }
+
+    public BlockPosition shift(EnumDirection enumdirection) {
+        return this.shift(enumdirection, 1);
+    }
+
+    public BlockPosition shift(EnumDirection enumdirection, int i) {
+        return i == 0 ? this : new BlockPosition(this.getX() + enumdirection.getAdjacentX() * i, this.getY() + enumdirection.getAdjacentY() * i, this.getZ() + enumdirection.getAdjacentZ() * i);
+    }
+
+    public BlockPosition c(BaseBlockPosition baseblockposition) {
+        return new BlockPosition(this.getY() * baseblockposition.getZ() - this.getZ() * baseblockposition.getY(), this.getZ() * baseblockposition.getX() - this.getX() * baseblockposition.getZ(), this.getX() * baseblockposition.getY() - this.getY() * baseblockposition.getX());
+    }
+
+    public long asLong() {
+        return ((long) this.getX() & BlockPosition.i) << BlockPosition.h | ((long) this.getY() & BlockPosition.j) << BlockPosition.g | ((long) this.getZ() & BlockPosition.k) << 0;
+    }
+
+    public static BlockPosition fromLong(long i) {
+        int j = (int) (i << 64 - BlockPosition.h - BlockPosition.d >> 64 - BlockPosition.d);
+        int k = (int) (i << 64 - BlockPosition.g - BlockPosition.f >> 64 - BlockPosition.f);
+        int l = (int) (i << 64 - BlockPosition.e >> 64 - BlockPosition.e);
+
+        return new BlockPosition(j, k, l);
+    }
+
+    public static Iterable<BlockPosition> a(BlockPosition blockposition, BlockPosition blockposition1) {
+        final BlockPosition blockposition2 = new BlockPosition(Math.min(blockposition.getX(), blockposition1.getX()), Math.min(blockposition.getY(), blockposition1.getY()), Math.min(blockposition.getZ(), blockposition1.getZ()));
+        final BlockPosition blockposition3 = new BlockPosition(Math.max(blockposition.getX(), blockposition1.getX()), Math.max(blockposition.getY(), blockposition1.getY()), Math.max(blockposition.getZ(), blockposition1.getZ()));
+
+        return new Iterable() {
+            public Iterator<BlockPosition> iterator() {
+                return new AbstractIterator() {
+                    private BlockPosition b = null;
+
+                    protected BlockPosition a() {
+                        if (this.b == null) {
+                            this.b = blockposition;
+                            return this.b;
+                        } else if (this.b.equals(blockposition1)) {
+                            return (BlockPosition) this.endOfData();
+                        } else {
+                            int i = this.b.getX();
+                            int j = this.b.getY();
+                            int k = this.b.getZ();
+
+                            if (i < blockposition1.getX()) {
+                                ++i;
+                            } else if (j < blockposition1.getY()) {
+                                i = blockposition.getX();
+                                ++j;
+                            } else if (k < blockposition1.getZ()) {
+                                i = blockposition.getX();
+                                j = blockposition.getY();
+                                ++k;
+                            }
+
+                            this.b = new BlockPosition(i, j, k);
+                            return this.b;
+                        }
+                    }
+
+                    protected Object computeNext() {
+                        return this.a();
+                    }
+                };
+            }
+        };
+    }
+
+    public BlockPosition h() {
+        return this;
+    }
+
+    public static Iterable<BlockPosition.MutableBlockPosition> b(BlockPosition blockposition, BlockPosition blockposition1) {
+        final BlockPosition blockposition2 = new BlockPosition(Math.min(blockposition.getX(), blockposition1.getX()), Math.min(blockposition.getY(), blockposition1.getY()), Math.min(blockposition.getZ(), blockposition1.getZ()));
+        final BlockPosition blockposition3 = new BlockPosition(Math.max(blockposition.getX(), blockposition1.getX()), Math.max(blockposition.getY(), blockposition1.getY()), Math.max(blockposition.getZ(), blockposition1.getZ()));
+
+        return new Iterable() {
+            public Iterator<BlockPosition.MutableBlockPosition> iterator() {
+                return new AbstractIterator() {
+                    private BlockPosition.MutableBlockPosition b = null;
+
+                    protected BlockPosition.MutableBlockPosition a() {
+                        if (this.b == null) {
+                            this.b = new BlockPosition.MutableBlockPosition(blockposition.getX(), blockposition.getY(), blockposition.getZ());
+                            return this.b;
+                        } else if (this.b.equals(blockposition1)) {
+                            return (BlockPosition.MutableBlockPosition) this.endOfData();
+                        } else {
+                            int i = this.b.getX();
+                            int j = this.b.getY();
+                            int k = this.b.getZ();
+
+                            if (i < blockposition1.getX()) {
+                                ++i;
+                            } else if (j < blockposition1.getY()) {
+                                i = blockposition.getX();
+                                ++j;
+                            } else if (k < blockposition1.getZ()) {
+                                i = blockposition.getX();
+                                j = blockposition.getY();
+                                ++k;
+                            }
+
+                            this.b.c = i;
+                            this.b.d = j;
+                            this.b.e = k;
+                            return this.b;
+                        }
+                    }
+
+                    protected Object computeNext() {
+                        return this.a();
+                    }
+                };
+            }
+        };
+    }
+
+    public BaseBlockPosition d(BaseBlockPosition baseblockposition) {
+        return this.c(baseblockposition);
+    }
+
+    public static final class PooledBlockPosition extends BlockPosition {
+
+        private int c;
+        private int d;
+        private int e;
+        private boolean f;
+        private static final List<BlockPosition.PooledBlockPosition> g = Lists.newArrayList();
+
+        private PooledBlockPosition(int i, int j, int k) {
+            super(0, 0, 0);
+            this.c = i;
+            this.d = j;
+            this.e = k;
+        }
+
+        public static BlockPosition.PooledBlockPosition s() {
+            return c(0, 0, 0);
+        }
+
+        public static BlockPosition.PooledBlockPosition c(double d0, double d1, double d2) {
+            return c(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2));
+        }
+
+        public static BlockPosition.PooledBlockPosition c(int i, int j, int k) {
+            List list = BlockPosition.PooledBlockPosition.g;
+
+            synchronized (BlockPosition.PooledBlockPosition.g) {
+                if (!BlockPosition.PooledBlockPosition.g.isEmpty()) {
+                    BlockPosition.PooledBlockPosition blockposition_pooledblockposition = (BlockPosition.PooledBlockPosition) BlockPosition.PooledBlockPosition.g.remove(BlockPosition.PooledBlockPosition.g.size() - 1);
+
+                    if (blockposition_pooledblockposition != null && blockposition_pooledblockposition.f) {
+                        blockposition_pooledblockposition.f = false;
+                        blockposition_pooledblockposition.d(i, j, k);
+                        return blockposition_pooledblockposition;
+                    }
+                }
+            }
+
+            return new BlockPosition.PooledBlockPosition(i, j, k);
+        }
+
+        public void t() {
+            List list = BlockPosition.PooledBlockPosition.g;
+
+            synchronized (BlockPosition.PooledBlockPosition.g) {
+                if (BlockPosition.PooledBlockPosition.g.size() < 100) {
+                    BlockPosition.PooledBlockPosition.g.add(this);
+                }
+
+                this.f = true;
+            }
+        }
+
+        public int getX() {
+            return this.c;
+        }
+
+        public int getY() {
+            return this.d;
+        }
+
+        public int getZ() {
+            return this.e;
+        }
+
+        public BlockPosition.PooledBlockPosition d(int i, int j, int k) {
+            if (this.f) {
+                BlockPosition.c.error("PooledMutableBlockPosition modified after it was released.", new Throwable());
+                this.f = false;
+            }
+
+            this.c = i;
+            this.d = j;
+            this.e = k;
+            return this;
+        }
+
+        public BlockPosition.PooledBlockPosition d(double d0, double d1, double d2) {
+            return this.d(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2));
+        }
+
+        public BlockPosition.PooledBlockPosition h(BaseBlockPosition baseblockposition) {
+            return this.d(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ());
+        }
+
+        public BlockPosition.PooledBlockPosition c(EnumDirection enumdirection) {
+            return this.d(this.c + enumdirection.getAdjacentX(), this.d + enumdirection.getAdjacentY(), this.e + enumdirection.getAdjacentZ());
+        }
+
+        public BaseBlockPosition d(BaseBlockPosition baseblockposition) {
+            return super.c(baseblockposition);
+        }
+    }
+
+    public static final class MutableBlockPosition extends BlockPosition {
+
+        private int c;
+        private int d;
+        private int e;
+
+        public MutableBlockPosition() {
+            this(0, 0, 0);
+        }
+
+        public MutableBlockPosition(BlockPosition blockposition) {
+            this(blockposition.getX(), blockposition.getY(), blockposition.getZ());
+        }
+
+        public MutableBlockPosition(int i, int j, int k) {
+            super(0, 0, 0);
+            this.c = i;
+            this.d = j;
+            this.e = k;
+        }
+
+        public int getX() {
+            return this.c;
+        }
+
+        public int getY() {
+            return this.d;
+        }
+
+        public int getZ() {
+            return this.e;
+        }
+
+        public BlockPosition.MutableBlockPosition c(int i, int j, int k) {
+            this.c = i;
+            this.d = j;
+            this.e = k;
+            return this;
+        }
+
+        public void c(EnumDirection enumdirection) {
+            this.c += enumdirection.getAdjacentX();
+            this.d += enumdirection.getAdjacentY();
+            this.e += enumdirection.getAdjacentZ();
+        }
+
+        public void p(int i) {
+            this.d = i;
+        }
+
+        public BlockPosition h() {
+            return new BlockPosition(this);
+        }
+
+        public BaseBlockPosition d(BaseBlockPosition baseblockposition) {
+            return super.c(baseblockposition);
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/server/BlockStateList.java b/src/main/java/net/minecraft/server/BlockStateList.java
new file mode 100644
index 0000000..a11c62f
--- /dev/null
+++ b/src/main/java/net/minecraft/server/BlockStateList.java
@@ -0,0 +1,325 @@
+package net.minecraft.server;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+public class BlockStateList {
+
+    private static final Pattern a = Pattern.compile("^[a-z0-9_]+$");
+    private static final Function<IBlockState<?>, String> b = new Function() {
+        public String a(IBlockState<?> iblockstate) {
+            return iblockstate == null ? "<NULL>" : iblockstate.a();
+        }
+
+        public Object apply(Object object) {
+            return this.a((IBlockState) object);
+        }
+    };
+    private final Block c;
+    private final ImmutableSortedMap<String, IBlockState<?>> d;
+    private final ImmutableList<IBlockData> e;
+
+    public BlockStateList(Block block, IBlockState<?>... aiblockstate) {
+        this.c = block;
+        HashMap hashmap = Maps.newHashMap();
+        IBlockState[] aiblockstate1 = aiblockstate;
+        int i = aiblockstate.length;
+
+        for (int j = 0; j < i; ++j) {
+            IBlockState iblockstate = aiblockstate1[j];
+
+            a(block, iblockstate);
+            hashmap.put(iblockstate.a(), iblockstate);
+        }
+
+        this.d = ImmutableSortedMap.copyOf(hashmap);
+        LinkedHashMap linkedhashmap = Maps.newLinkedHashMap();
+        ArrayList arraylist = Lists.newArrayList();
+        Iterable iterable = IteratorUtils.a(this.e());
+        Iterator iterator = iterable.iterator();
+
+        while (iterator.hasNext()) {
+            List list = (List) iterator.next();
+            Map map = MapGeneratorUtils.b(this.d.values(), list);
+            BlockStateList.BlockData blockstatelist_blockdata = new BlockStateList.BlockData(block, ImmutableMap.copyOf(map), null);
+
+            linkedhashmap.put(map, blockstatelist_blockdata);
+            arraylist.add(blockstatelist_blockdata);
+        }
+
+        iterator = arraylist.iterator();
+
+        while (iterator.hasNext()) {
+            BlockStateList.BlockData blockstatelist_blockdata1 = (BlockStateList.BlockData) iterator.next();
+
+            blockstatelist_blockdata1.a((Map) linkedhashmap);
+        }
+
+        this.e = ImmutableList.copyOf(arraylist);
+    }
+
+    public static <T extends Comparable<T>> String a(Block block, IBlockState<T> iblockstate) {
+        String s = iblockstate.a();
+
+        if (!BlockStateList.a.matcher(s).matches()) {
+            throw new IllegalArgumentException("Block: " + block.getClass() + " has invalidly named property: " + s);
+        } else {
+            for (T t : iblockstate.c()) {
+                String s1 = iblockstate.a(t);
+
+                if (!a.matcher(s1).matches())
+                {
+                    throw new IllegalArgumentException("Block: " + block.getClass() + " has property: " + s + " with invalidly named value: " + s1);
+                }
+            }
+        }
+        return s;
+    }
+
+    public ImmutableList<IBlockData> a() {
+        return this.e;
+    }
+
+    private List<Iterable<Comparable<?>>> e() {
+        ArrayList arraylist = Lists.newArrayList();
+        ImmutableCollection immutablecollection = this.d.values();
+        Iterator iterator = immutablecollection.iterator();
+
+        while (iterator.hasNext()) {
+            IBlockState iblockstate = (IBlockState) iterator.next();
+
+            arraylist.add(iblockstate.c());
+        }
+
+        return arraylist;
+    }
+
+    public IBlockData getBlockData() {
+        return (IBlockData) this.e.get(0);
+    }
+
+    public Block getBlock() {
+        return this.c;
+    }
+
+    public Collection<IBlockState<?>> d() {
+        return this.d.values();
+    }
+
+    public String toString() {
+        return Objects.toStringHelper(this).add("block", Block.REGISTRY.b(this.c)).add("properties", Iterables.transform(this.d.values(), BlockStateList.b)).toString();
+    }
+
+    static class BlockData extends BlockDataAbstract {
+
+        private final Block a;
+        private final ImmutableMap<IBlockState<?>, Comparable<?>> b;
+        private ImmutableTable<IBlockState<?>, Comparable<?>, IBlockData> c;
+
+        private BlockData(Block block, ImmutableMap<IBlockState<?>, Comparable<?>> immutablemap) {
+            this.a = block;
+            this.b = immutablemap;
+        }
+
+        public Collection<IBlockState<?>> r() {
+            return Collections.unmodifiableCollection(this.b.keySet());
+        }
+
+        public <T extends Comparable<T>> T get(IBlockState<T> iblockstate) {
+            if (!this.b.containsKey(iblockstate)) {
+                throw new IllegalArgumentException("Cannot get property " + iblockstate + " as it does not exist in " + this.a.t());
+            } else {
+                return iblockstate.b().cast(this.b.get(iblockstate));
+            }
+        }
+
+        public <T extends Comparable<T>, V extends T> IBlockData set(IBlockState<T> iblockstate, V v0) {
+            if (!this.b.containsKey(iblockstate)) {
+                throw new IllegalArgumentException("Cannot set property " + iblockstate + " as it does not exist in " + this.a.t());
+            } else if (!iblockstate.c().contains(v0)) {
+                throw new IllegalArgumentException("Cannot set property " + iblockstate + " to " + v0 + " on block " + Block.REGISTRY.b(this.a) + ", it is not an allowed value");
+            } else {
+                return (IBlockData) (this.b.get(iblockstate) == v0 ? this : (IBlockData) this.c.get(iblockstate, v0));
+            }
+        }
+
+        public ImmutableMap<IBlockState<?>, Comparable<?>> s() {
+            return this.b;
+        }
+
+        public Block getBlock() {
+            return this.a;
+        }
+
+        public boolean equals(Object object) {
+            return this == object;
+        }
+
+        public int hashCode() {
+            return this.b.hashCode();
+        }
+
+        public void a(Map<Map<IBlockState<?>, Comparable<?>>, BlockStateList.BlockData> map) {
+            if (this.c != null) {
+                throw new IllegalStateException();
+            } else {
+                HashBasedTable hashbasedtable = HashBasedTable.create();
+                Iterator iterator = this.b.entrySet().iterator();
+
+                while (iterator.hasNext()) {
+                    Entry entry = (Entry) iterator.next();
+                    IBlockState iblockstate = (IBlockState) entry.getKey();
+                    Iterator iterator1 = iblockstate.c().iterator();
+
+                    while (iterator1.hasNext()) {
+                        Comparable comparable = (Comparable) iterator1.next();
+
+                        if (comparable != entry.getValue()) {
+                            hashbasedtable.put(iblockstate, comparable, map.get(this.b(iblockstate, comparable)));
+                        }
+                    }
+                }
+
+                this.c = ImmutableTable.copyOf(hashbasedtable);
+            }
+        }
+
+        private Map<IBlockState<?>, Comparable<?>> b(IBlockState<?> iblockstate, Comparable<?> comparable) {
+            HashMap hashmap = Maps.newHashMap(this.b);
+
+            hashmap.put(iblockstate, comparable);
+            return hashmap;
+        }
+
+        public Material getMaterial() {
+            return this.a.q(this);
+        }
+
+        public boolean b() {
+            return this.a.l(this);
+        }
+
+        public int c() {
+            return this.a.m(this);
+        }
+
+        public int d() {
+            return this.a.o(this);
+        }
+
+        public boolean f() {
+            return this.a.p(this);
+        }
+
+        public MaterialMapColor g() {
+            return this.a.r(this);
+        }
+
+        public IBlockData a(EnumBlockRotation enumblockrotation) {
+            return this.a.a((IBlockData) this, enumblockrotation);
+        }
+
+        public IBlockData a(EnumBlockMirror enumblockmirror) {
+            return this.a.a((IBlockData) this, enumblockmirror);
+        }
+
+        public boolean h() {
+            return this.a.c((IBlockData) this);
+        }
+
+        public EnumRenderType i() {
+            return this.a.a((IBlockData) this);
+        }
+
+        public boolean k() {
+            return this.a.s(this);
+        }
+
+        public boolean l() {
+            return this.a.isOccluding(this);
+        }
+
+        public boolean m() {
+            return this.a.isPowerSource(this);
+        }
+
+        public int a(IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+            return this.a.b((IBlockData) this, iblockaccess, blockposition, enumdirection);
+        }
+
+        public boolean n() {
+            return this.a.isComplexRedstone(this);
+        }
+
+        public int a(World world, BlockPosition blockposition) {
+            return this.a.d(this, world, blockposition);
+        }
+
+        public float b(World world, BlockPosition blockposition) {
+            return this.a.b(this, world, blockposition);
+        }
+
+        public float a(EntityHuman entityhuman, World world, BlockPosition blockposition) {
+            return this.a.getDamage(this, entityhuman, world, blockposition);
+        }
+
+        public int b(IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
+            return this.a.c(this, iblockaccess, blockposition, enumdirection);
+        }
+
+        public EnumPistonReaction o() {
+            return this.a.h(this);
+        }
+
+        public IBlockData b(IBlockAccess iblockaccess, BlockPosition blockposition) {
+            return this.a.updateState(this, iblockaccess, blockposition);
+        }
+
+        public boolean p() {
+            return this.a.b((IBlockData) this);
+        }
+
+        public AxisAlignedBB d(World world, BlockPosition blockposition) {
+            return this.a.a((IBlockData) this, world, blockposition);
+        }
+
+        public void a(World world, BlockPosition blockposition, AxisAlignedBB axisalignedbb, List<AxisAlignedBB> list, Entity entity) {
+            this.a.a((IBlockData) this, world, blockposition, axisalignedbb, list, entity);
+        }
+
+        public AxisAlignedBB c(IBlockAccess iblockaccess, BlockPosition blockposition) {
+            return this.a.a((IBlockData) this, iblockaccess, blockposition);
+        }
+
+        public MovingObjectPosition a(World world, BlockPosition blockposition, Vec3D vec3d, Vec3D vec3d1) {
+            return this.a.a(this, world, blockposition, vec3d, vec3d1);
+        }
+
+        public boolean q() {
+            return this.a.k(this);
+        }
+
+        BlockData(Block block, ImmutableMap immutablemap, Object object) {
+            this(block, immutablemap);
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderFlat.java b/src/main/java/net/minecraft/server/ChunkProviderFlat.java
new file mode 100644
index 0000000..17e0b8e
--- /dev/null
+++ b/src/main/java/net/minecraft/server/ChunkProviderFlat.java
@@ -0,0 +1,214 @@
+package net.minecraft.server;
+
+import com.google.common.collect.Lists;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+public class ChunkProviderFlat implements ChunkGenerator {
+
+    private final World a;
+    private final Random b;
+    private final IBlockData[] c = new IBlockData[256];
+    private final WorldGenFlatInfo d;
+    private final List<StructureGenerator> e = Lists.newArrayList();
+    private final boolean f;
+    private final boolean g;
+    private WorldGenLakes h;
+    private WorldGenLakes i;
+
+    public ChunkProviderFlat(World world, long i, boolean flag, String s) {
+        this.a = world;
+        this.b = new Random(i);
+        this.d = WorldGenFlatInfo.a(s);
+        if (flag) {
+            Map map = this.d.b();
+
+            if (map.containsKey("village")) {
+                Map map1 = (Map) map.get("village");
+
+                if (!map1.containsKey("size")) {
+                    map1.put("size", "1");
+                }
+
+                this.e.add(new WorldGenVillage(map1));
+            }
+
+            if (map.containsKey("biome_1")) {
+                this.e.add(new WorldGenLargeFeature((Map) map.get("biome_1")));
+            }
+
+            if (map.containsKey("mineshaft")) {
+                this.e.add(new WorldGenMineshaft((Map) map.get("mineshaft")));
+            }
+
+            if (map.containsKey("stronghold")) {
+                this.e.add(new WorldGenStronghold((Map) map.get("stronghold")));
+            }
+
+            if (map.containsKey("oceanmonument")) {
+                this.e.add(new WorldGenMonument((Map) map.get("oceanmonument")));
+            }
+        }
+
+        if (this.d.b().containsKey("lake")) {
+            this.h = new WorldGenLakes(Blocks.WATER);
+        }
+
+        if (this.d.b().containsKey("lava_lake")) {
+            this.i = new WorldGenLakes(Blocks.LAVA);
+        }
+
+        this.g = this.d.b().containsKey("dungeon");
+        int j = 0;
+        int k = 0;
+        boolean flag1 = true;
+        Iterator iterator = this.d.c().iterator();
+
+        while (iterator.hasNext()) {
+            WorldGenFlatLayerInfo worldgenflatlayerinfo = (WorldGenFlatLayerInfo) iterator.next();
+
+            for (int l = worldgenflatlayerinfo.d(); l < worldgenflatlayerinfo.d() + worldgenflatlayerinfo.b(); ++l) {
+                IBlockData iblockdata = worldgenflatlayerinfo.c();
+
+                if (iblockdata.getBlock() != Blocks.AIR) {
+                    flag1 = false;
+                    this.c[l] = iblockdata;
+                }
+            }
+
+            if (worldgenflatlayerinfo.c().getBlock() == Blocks.AIR) {
+                k += worldgenflatlayerinfo.b();
+            } else {
+                j += worldgenflatlayerinfo.b() + k;
+                k = 0;
+            }
+        }
+
+        world.b(j);
+        this.f = flag1 && this.d.a() != BiomeBase.a(Biomes.P) ? false : this.d.b().containsKey("decoration");
+    }
+
+    public Chunk getOrCreateChunk(int i, int j) {
+        ChunkSnapshot chunksnapshot = new ChunkSnapshot();
+
+        int k;
+
+        for (int l = 0; l < this.c.length; ++l) {
+            IBlockData iblockdata = this.c[l];
+
+            if (iblockdata != null) {
+                for (int i1 = 0; i1 < 16; ++i1) {
+                    for (k = 0; k < 16; ++k) {
+                        chunksnapshot.a(i1, l, k, iblockdata);
+                    }
+                }
+            }
+        }
+
+        Iterator iterator = this.e.iterator();
+
+        while (iterator.hasNext()) {
+            WorldGenBase worldgenbase = (WorldGenBase) iterator.next();
+
+            worldgenbase.a(this.a, i, j, chunksnapshot);
+        }
+
+        Chunk chunk = new Chunk(this.a, chunksnapshot, i, j);
+        BiomeBase[] abiomebase = this.a.getWorldChunkManager().getBiomeBlock((BiomeBase[]) null, i * 16, j * 16, 16, 16);
+        byte[] abyte = chunk.getBiomeIndex();
+
+        for (k = 0; k < abyte.length; ++k) {
+            abyte[k] = (byte) BiomeBase.a(abiomebase[k]);
+        }
+
+        chunk.initLighting();
+        return chunk;
+    }
+
+    public void recreateStructures(int i, int j) {
+        int k = i * 16;
+        int l = j * 16;
+        BlockPosition blockposition = new BlockPosition(k, 0, l);
+        BiomeBase biomebase = this.a.getBiome(new BlockPosition(k + 16, 0, l + 16));
+        boolean flag = false;
+
+        this.b.setSeed(this.a.getSeed());
+        long i1 = this.b.nextLong() / 2L * 2L + 1L;
+        long j1 = this.b.nextLong() / 2L * 2L + 1L;
+
+        this.b.setSeed((long) i * i1 + (long) j * j1 ^ this.a.getSeed());
+        ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
+        Iterator iterator = this.e.iterator();
+
+        while (iterator.hasNext()) {
+            StructureGenerator structuregenerator = (StructureGenerator) iterator.next();
+            boolean flag1 = structuregenerator.a(this.a, this.b, chunkcoordintpair);
+
+            if (structuregenerator instanceof WorldGenVillage) {
+                flag |= flag1;
+            }
+        }
+
+        if (this.h != null && !flag && this.b.nextInt(4) == 0) {
+            this.h.generate(this.a, this.b, blockposition.a(this.b.nextInt(16) + 8, this.b.nextInt(256), this.b.nextInt(16) + 8));
+        }
+
+        if (this.i != null && !flag && this.b.nextInt(8) == 0) {
+            BlockPosition blockposition1 = blockposition.a(this.b.nextInt(16) + 8, this.b.nextInt(this.b.nextInt(248) + 8), this.b.nextInt(16) + 8);
+
+            if (blockposition1.getY() < this.a.K() || this.b.nextInt(10) == 0) {
+                this.i.generate(this.a, this.b, blockposition1);
+            }
+        }
+
+        if (this.g) {
+            for (int k1 = 0; k1 < 8; ++k1) {
+                (new WorldGenDungeons()).generate(this.a, this.b, blockposition.a(this.b.nextInt(16) + 8, this.b.nextInt(256), this.b.nextInt(16) + 8));
+            }
+        }
+
+        if (this.f) {
+            biomebase.a(this.a, this.b, blockposition);
+        }
+
+    }
+
+    public boolean a(Chunk chunk, int i, int j) {
+        return false;
+    }
+
+    public List<BiomeBase.BiomeMeta> getMobsFor(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
+        BiomeBase biomebase = this.a.getBiome(blockposition);
+
+        return biomebase.getMobs(enumcreaturetype);
+    }
+
+    public BlockPosition findNearestMapFeature(World world, String s, BlockPosition blockposition) {
+        if ("Stronghold".equals(s)) {
+            Iterator iterator = this.e.iterator();
+
+            while (iterator.hasNext()) {
+                StructureGenerator structuregenerator = (StructureGenerator) iterator.next();
+
+                if (structuregenerator instanceof WorldGenStronghold) {
+                    return structuregenerator.getNearestGeneratedFeature(world, blockposition);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public void recreateStructures(Chunk chunk, int i, int j) {
+        Iterator iterator = this.e.iterator();
+
+        while (iterator.hasNext()) {
+            StructureGenerator structuregenerator = (StructureGenerator) iterator.next();
+
+            structuregenerator.a(this.a, i, j, (ChunkSnapshot) null);
+        }
+
+    }
+}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderGenerate.java b/src/main/java/net/minecraft/server/ChunkProviderGenerate.java
new file mode 100644
index 0000000..88d0374
--- /dev/null
+++ b/src/main/java/net/minecraft/server/ChunkProviderGenerate.java
@@ -0,0 +1,449 @@
+package net.minecraft.server;
+
+import java.util.List;
+import java.util.Random;
+
+public class ChunkProviderGenerate implements ChunkGenerator {
+
+    protected static final IBlockData a = Blocks.STONE.getBlockData();
+    private final Random i;
+    private final NoiseGeneratorOctaves j;
+    private final NoiseGeneratorOctaves k;
+    private final NoiseGeneratorOctaves l;
+    private final NoiseGenerator3 m;
+    public NoiseGeneratorOctaves b;
+    public NoiseGeneratorOctaves c;
+    public NoiseGeneratorOctaves d;
+    private final World n;
+    private final boolean o;
+    private final WorldType p;
+    private final double[] q;
+    private final float[] r;
+    private CustomWorldSettingsFinal s;
+    private IBlockData t;
+    private double[] u;
+    private final WorldGenBase v;
+    private final WorldGenStronghold w;
+    private final WorldGenVillage x;
+    private final WorldGenMineshaft y;
+    private final WorldGenLargeFeature z;
+    private final WorldGenBase A;
+    private final WorldGenMonument B;
+    private BiomeBase[] C;
+    double[] e;
+    double[] f;
+    double[] g;
+    double[] h;
+
+    public ChunkProviderGenerate(World world, long i, boolean flag, String s) {
+        this.t = Blocks.WATER.getBlockData();
+        this.u = new double[256];
+        this.v = new WorldGenCaves();
+        this.w = new WorldGenStronghold();
+        this.x = new WorldGenVillage();
+        this.y = new WorldGenMineshaft();
+        this.z = new WorldGenLargeFeature();
+        this.A = new WorldGenCanyon();
+        this.B = new WorldGenMonument();
+        this.n = world;
+        this.o = flag;
+        this.p = world.getWorldData().getType();
+        this.i = new Random(i);
+        this.j = new NoiseGeneratorOctaves(this.i, 16);
+        this.k = new NoiseGeneratorOctaves(this.i, 16);
+        this.l = new NoiseGeneratorOctaves(this.i, 8);
+        this.m = new NoiseGenerator3(this.i, 4);
+        this.b = new NoiseGeneratorOctaves(this.i, 10);
+        this.c = new NoiseGeneratorOctaves(this.i, 16);
+        this.d = new NoiseGeneratorOctaves(this.i, 8);
+        this.q = new double[825];
+        this.r = new float[25];
+
+        for (int j = -2; j <= 2; ++j) {
+            for (int k = -2; k <= 2; ++k) {
+                float f = 10.0F / MathHelper.c((float) (j * j + k * k) + 0.2F);
+
+                this.r[j + 2 + (k + 2) * 5] = f;
+            }
+        }
+
+        if (s != null) {
+            this.s = CustomWorldSettingsFinal.CustomWorldSettings.a(s).b();
+            this.t = this.s.E ? Blocks.LAVA.getBlockData() : Blocks.WATER.getBlockData();
+            world.b(this.s.q);
+        }
+
+    }
+
+    public void a(int i, int j, ChunkSnapshot chunksnapshot) {
+        this.C = this.n.getWorldChunkManager().getBiomes(this.C, i * 4 - 2, j * 4 - 2, 10, 10);
+        this.a(i * 4, 0, j * 4);
+
+        for (int k = 0; k < 4; ++k) {
+            int l = k * 5;
+            int i1 = (k + 1) * 5;
+
+            for (int j1 = 0; j1 < 4; ++j1) {
+                int k1 = (l + j1) * 33;
+                int l1 = (l + j1 + 1) * 33;
+                int i2 = (i1 + j1) * 33;
+                int j2 = (i1 + j1 + 1) * 33;
+
+                for (int k2 = 0; k2 < 32; ++k2) {
+                    double d0 = 0.125D;
+                    double d1 = this.q[k1 + k2];
+                    double d2 = this.q[l1 + k2];
+                    double d3 = this.q[i2 + k2];
+                    double d4 = this.q[j2 + k2];
+                    double d5 = (this.q[k1 + k2 + 1] - d1) * d0;
+                    double d6 = (this.q[l1 + k2 + 1] - d2) * d0;
+                    double d7 = (this.q[i2 + k2 + 1] - d3) * d0;
+                    double d8 = (this.q[j2 + k2 + 1] - d4) * d0;
+
+                    for (int l2 = 0; l2 < 8; ++l2) {
+                        double d9 = 0.25D;
+                        double d10 = d1;
+                        double d11 = d2;
+                        double d12 = (d3 - d1) * d9;
+                        double d13 = (d4 - d2) * d9;
+
+                        for (int i3 = 0; i3 < 4; ++i3) {
+                            double d14 = 0.25D;
+                            double d15 = (d11 - d10) * d14;
+                            double d16 = d10 - d15;
+
+                            for (int j3 = 0; j3 < 4; ++j3) {
+                                if ((d16 += d15) > 0.0D) {
+                                    chunksnapshot.a(k * 4 + i3, k2 * 8 + l2, j1 * 4 + j3, ChunkProviderGenerate.a);
+                                } else if (k2 * 8 + l2 < this.s.q) {
+                                    chunksnapshot.a(k * 4 + i3, k2 * 8 + l2, j1 * 4 + j3, this.t);
+                                }
+                            }
+
+                            d10 += d12;
+                            d11 += d13;
+                        }
+
+                        d1 += d5;
+                        d2 += d6;
+                        d3 += d7;
+                        d4 += d8;
+                    }
+                }
+            }
+        }
+
+    }
+
+    public void a(int i, int j, ChunkSnapshot chunksnapshot, BiomeBase[] abiomebase) {
+        double d0 = 0.03125D;
+
+        this.u = this.m.a(this.u, (double) (i * 16), (double) (j * 16), 16, 16, d0 * 2.0D, d0 * 2.0D, 1.0D);
+
+        for (int k = 0; k < 16; ++k) {
+            for (int l = 0; l < 16; ++l) {
+                BiomeBase biomebase = abiomebase[l + k * 16];
+
+                biomebase.a(this.n, this.i, chunksnapshot, i * 16 + k, j * 16 + l, this.u[l + k * 16]);
+            }
+        }
+
+    }
+
+    public Chunk getOrCreateChunk(int i, int j) {
+        this.i.setSeed((long) i * 341873128712L + (long) j * 132897987541L);
+        ChunkSnapshot chunksnapshot = new ChunkSnapshot();
+
+        this.a(i, j, chunksnapshot);
+        this.C = this.n.getWorldChunkManager().getBiomeBlock(this.C, i * 16, j * 16, 16, 16);
+        this.a(i, j, chunksnapshot, this.C);
+        if (this.s.r) {
+            this.v.a(this.n, i, j, chunksnapshot);
+        }
+
+        if (this.s.z) {
+            this.A.a(this.n, i, j, chunksnapshot);
+        }
+
+        if (this.o) {
+            if (this.s.w) {
+                this.y.a(this.n, i, j, chunksnapshot);
+            }
+
+            if (this.s.v) {
+                this.x.a(this.n, i, j, chunksnapshot);
+            }
+
+            if (this.s.u) {
+                this.w.a(this.n, i, j, chunksnapshot);
+            }
+
+            if (this.s.x) {
+                this.z.a(this.n, i, j, chunksnapshot);
+            }
+
+            if (this.s.y) {
+                this.B.a(this.n, i, j, chunksnapshot);
+            }
+        }
+
+        Chunk chunk = new Chunk(this.n, chunksnapshot, i, j);
+        byte[] abyte = chunk.getBiomeIndex();
+
+        for (int k = 0; k < abyte.length; ++k) {
+            abyte[k] = (byte) BiomeBase.a(this.C[k]);
+        }
+
+        chunk.initLighting();
+        return chunk;
+    }
+
+    private void a(int i, int j, int k) {
+        this.h = this.c.a(this.h, i, k, 5, 5, (double) this.s.e, (double) this.s.f, (double) this.s.g);
+        float f = this.s.a;
+        float f1 = this.s.b;
+
+        this.e = this.l.a(this.e, i, j, k, 5, 33, 5, (double) (f / this.s.h), (double) (f1 / this.s.i), (double) (f / this.s.j));
+        this.f = this.j.a(this.f, i, j, k, 5, 33, 5, (double) f, (double) f1, (double) f);
+        this.g = this.k.a(this.g, i, j, k, 5, 33, 5, (double) f, (double) f1, (double) f);
+        boolean flag = false;
+        boolean flag1 = false;
+        int l = 0;
+        int i1 = 0;
+
+        for (int j1 = 0; j1 < 5; ++j1) {
+            for (int k1 = 0; k1 < 5; ++k1) {
+                float f2 = 0.0F;
+                float f3 = 0.0F;
+                float f4 = 0.0F;
+                byte b0 = 2;
+                BiomeBase biomebase = this.C[j1 + 2 + (k1 + 2) * 10];
+
+                for (int l1 = -b0; l1 <= b0; ++l1) {
+                    for (int i2 = -b0; i2 <= b0; ++i2) {
+                        BiomeBase biomebase1 = this.C[j1 + l1 + 2 + (k1 + i2 + 2) * 10];
+                        float f5 = this.s.n + biomebase1.j() * this.s.m;
+                        float f6 = this.s.p + biomebase1.m() * this.s.o;
+
+                        if (this.p == WorldType.AMPLIFIED && f5 > 0.0F) {
+                            f5 = 1.0F + f5 * 2.0F;
+                            f6 = 1.0F + f6 * 4.0F;
+                        }
+
+                        float f7 = this.r[l1 + 2 + (i2 + 2) * 5] / (f5 + 2.0F);
+
+                        if (biomebase1.j() > biomebase.j()) {
+                            f7 /= 2.0F;
+                        }
+
+                        f2 += f6 * f7;
+                        f3 += f5 * f7;
+                        f4 += f7;
+                    }
+                }
+
+                f2 /= f4;
+                f3 /= f4;
+                f2 = f2 * 0.9F + 0.1F;
+                f3 = (f3 * 4.0F - 1.0F) / 8.0F;
+                double d0 = this.h[i1] / 8000.0D;
+
+                if (d0 < 0.0D) {
+                    d0 = -d0 * 0.3D;
+                }
+
+                d0 = d0 * 3.0D - 2.0D;
+                if (d0 < 0.0D) {
+                    d0 /= 2.0D;
+                    if (d0 < -1.0D) {
+                        d0 = -1.0D;
+                    }
+
+                    d0 /= 1.4D;
+                    d0 /= 2.0D;
+                } else {
+                    if (d0 > 1.0D) {
+                        d0 = 1.0D;
+                    }
+
+                    d0 /= 8.0D;
+                }
+
+                ++i1;
+                double d1 = (double) f3;
+                double d2 = (double) f2;
+
+                d1 += d0 * 0.2D;
+                d1 = d1 * (double) this.s.k / 8.0D;
+                double d3 = (double) this.s.k + d1 * 4.0D;
+
+                for (int j2 = 0; j2 < 33; ++j2) {
+                    double d4 = ((double) j2 - d3) * (double) this.s.l * 128.0D / 256.0D / d2;
+
+                    if (d4 < 0.0D) {
+                        d4 *= 4.0D;
+                    }
+
+                    double d5 = this.f[l] / (double) this.s.d;
+                    double d6 = this.g[l] / (double) this.s.c;
+                    double d7 = (this.e[l] / 10.0D + 1.0D) / 2.0D;
+                    double d8 = MathHelper.b(d5, d6, d7) - d4;
+
+                    if (j2 > 29) {
+                        double d9 = (double) ((float) (j2 - 29) / 3.0F);
+
+                        d8 = d8 * (1.0D - d9) + -10.0D * d9;
+                    }
+
+                    this.q[l] = d8;
+                    ++l;
+                }
+            }
+        }
+
+    }
+
+    public void recreateStructures(int i, int j) {
+        BlockFalling.instaFall = true;
+        int k = i * 16;
+        int l = j * 16;
+        BlockPosition blockposition = new BlockPosition(k, 0, l);
+        BiomeBase biomebase = this.n.getBiome(blockposition.a(16, 0, 16));
+
+        this.i.setSeed(this.n.getSeed());
+        long i1 = this.i.nextLong() / 2L * 2L + 1L;
+        long j1 = this.i.nextLong() / 2L * 2L + 1L;
+
+        this.i.setSeed((long) i * i1 + (long) j * j1 ^ this.n.getSeed());
+        boolean flag = false;
+        ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
+
+        if (this.o) {
+            if (this.s.w) {
+                this.y.a(this.n, this.i, chunkcoordintpair);
+            }
+
+            if (this.s.v) {
+                flag = this.x.a(this.n, this.i, chunkcoordintpair);
+            }
+
+            if (this.s.u) {
+                this.w.a(this.n, this.i, chunkcoordintpair);
+            }
+
+            if (this.s.x) {
+                this.z.a(this.n, this.i, chunkcoordintpair);
+            }
+
+            if (this.s.y) {
+                this.B.a(this.n, this.i, chunkcoordintpair);
+            }
+        }
+
+        int k1;
+        int l1;
+        int i2;
+
+        if (biomebase != Biomes.d && biomebase != Biomes.s && this.s.A && !flag && this.i.nextInt(this.s.B) == 0) {
+            k1 = this.i.nextInt(16) + 8;
+            l1 = this.i.nextInt(256);
+            i2 = this.i.nextInt(16) + 8;
+            (new WorldGenLakes(Blocks.WATER)).generate(this.n, this.i, blockposition.a(k1, l1, i2));
+        }
+
+        if (!flag && this.i.nextInt(this.s.D / 10) == 0 && this.s.C) {
+            k1 = this.i.nextInt(16) + 8;
+            l1 = this.i.nextInt(this.i.nextInt(248) + 8);
+            i2 = this.i.nextInt(16) + 8;
+            if (l1 < this.n.K() || this.i.nextInt(this.s.D / 8) == 0) {
+                (new WorldGenLakes(Blocks.LAVA)).generate(this.n, this.i, blockposition.a(k1, l1, i2));
+            }
+        }
+
+        if (this.s.s) {
+            for (k1 = 0; k1 < this.s.t; ++k1) {
+                l1 = this.i.nextInt(16) + 8;
+                i2 = this.i.nextInt(256);
+                int j2 = this.i.nextInt(16) + 8;
+
+                (new WorldGenDungeons()).generate(this.n, this.i, blockposition.a(l1, i2, j2));
+            }
+        }
+
+        biomebase.a(this.n, this.i, new BlockPosition(k, 0, l));
+        SpawnerCreature.a(this.n, biomebase, k + 8, l + 8, 16, 16, this.i);
+        blockposition = blockposition.a(8, 0, 8);
+
+        for (k1 = 0; k1 < 16; ++k1) {
+            for (l1 = 0; l1 < 16; ++l1) {
+                BlockPosition blockposition1 = this.n.p(blockposition.a(k1, 0, l1));
+                BlockPosition blockposition2 = blockposition1.down();
+
+                if (this.n.u(blockposition2)) {
+                    this.n.setTypeAndData(blockposition2, Blocks.ICE.getBlockData(), 2);
+                }
+
+                if (this.n.f(blockposition1, true)) {
+                    this.n.setTypeAndData(blockposition1, Blocks.SNOW_LAYER.getBlockData(), 2);
+                }
+            }
+        }
+
+        BlockFalling.instaFall = false;
+    }
+
+    public boolean a(Chunk chunk, int i, int j) {
+        boolean flag = false;
+
+        if (this.s.y && this.o && chunk.x() < 3600L) {
+            flag |= this.B.a(this.n, this.i, new ChunkCoordIntPair(i, j));
+        }
+
+        return flag;
+    }
+
+    public List<BiomeBase.BiomeMeta> getMobsFor(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
+        BiomeBase biomebase = this.n.getBiome(blockposition);
+
+        if (this.o) {
+            if (enumcreaturetype == EnumCreatureType.MONSTER && this.z.a(blockposition)) {
+                return this.z.b();
+            }
+
+            if (enumcreaturetype == EnumCreatureType.MONSTER && this.s.y && this.B.b(this.n, blockposition)) {
+                return this.B.b();
+            }
+        }
+
+        return biomebase.getMobs(enumcreaturetype);
+    }
+
+    public BlockPosition findNearestMapFeature(World world, String s, BlockPosition blockposition) {
+        return "Stronghold".equals(s) && this.w != null ? this.w.getNearestGeneratedFeature(world, blockposition) : null;
+    }
+
+    public void recreateStructures(Chunk chunk, int i, int j) {
+        if (this.o) {
+            if (this.s.w) {
+                this.y.a(this.n, i, j, (ChunkSnapshot) null);
+            }
+
+            if (this.s.v) {
+                this.x.a(this.n, i, j, (ChunkSnapshot) null);
+            }
+
+            if (this.s.u) {
+                this.w.a(this.n, i, j, (ChunkSnapshot) null);
+            }
+
+            if (this.s.x) {
+                this.z.a(this.n, i, j, (ChunkSnapshot) null);
+            }
+
+            if (this.s.y) {
+                this.B.a(this.n, i, j, (ChunkSnapshot) null);
+            }
+        }
+
+    }
+}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderHell.java b/src/main/java/net/minecraft/server/ChunkProviderHell.java
new file mode 100644
index 0000000..0150efd
--- /dev/null
+++ b/src/main/java/net/minecraft/server/ChunkProviderHell.java
@@ -0,0 +1,369 @@
+package net.minecraft.server;
+
+import java.util.List;
+import java.util.Random;
+
+public class ChunkProviderHell implements ChunkGenerator {
+
+    protected static final IBlockData a = Blocks.AIR.getBlockData();
+    protected static final IBlockData b = Blocks.NETHERRACK.getBlockData();
+    protected static final IBlockData c = Blocks.BEDROCK.getBlockData();
+    protected static final IBlockData d = Blocks.LAVA.getBlockData();
+    protected static final IBlockData e = Blocks.GRAVEL.getBlockData();
+    protected static final IBlockData f = Blocks.SOUL_SAND.getBlockData();
+    private final World n;
+    private final boolean o;
+    private final Random p;
+    private double[] q = new double[256];
+    private double[] r = new double[256];
+    private double[] s = new double[256];
+    private double[] t;
+    private final NoiseGeneratorOctaves u;
+    private final NoiseGeneratorOctaves v;
+    private final NoiseGeneratorOctaves w;
+    private final NoiseGeneratorOctaves x;
+    private final NoiseGeneratorOctaves y;
+    public final NoiseGeneratorOctaves g;
+    public final NoiseGeneratorOctaves h;
+    private final WorldGenFire z = new WorldGenFire();
+    private final WorldGenLightStone1 A = new WorldGenLightStone1();
+    private final WorldGenLightStone2 B = new WorldGenLightStone2();
+    private final WorldGenerator C;
+    private final WorldGenHellLava D;
+    private final WorldGenHellLava E;
+    private final WorldGenMushrooms F;
+    private final WorldGenMushrooms G;
+    private final WorldGenNether H;
+    private final WorldGenBase I;
+    double[] i;
+    double[] j;
+    double[] k;
+    double[] l;
+    double[] m;
+
+    public ChunkProviderHell(World world, boolean flag, long i) {
+        this.C = new WorldGenMinable(Blocks.QUARTZ_ORE.getBlockData(), 14, BlockPredicate.a(Blocks.NETHERRACK));
+        this.D = new WorldGenHellLava(Blocks.FLOWING_LAVA, true);
+        this.E = new WorldGenHellLava(Blocks.FLOWING_LAVA, false);
+        this.F = new WorldGenMushrooms(Blocks.BROWN_MUSHROOM);
+        this.G = new WorldGenMushrooms(Blocks.RED_MUSHROOM);
+        this.H = new WorldGenNether();
+        this.I = new WorldGenCavesHell();
+        this.n = world;
+        this.o = flag;
+        this.p = new Random(i);
+        this.u = new NoiseGeneratorOctaves(this.p, 16);
+        this.v = new NoiseGeneratorOctaves(this.p, 16);
+        this.w = new NoiseGeneratorOctaves(this.p, 8);
+        this.x = new NoiseGeneratorOctaves(this.p, 4);
+        this.y = new NoiseGeneratorOctaves(this.p, 4);
+        this.g = new NoiseGeneratorOctaves(this.p, 10);
+        this.h = new NoiseGeneratorOctaves(this.p, 16);
+        world.b(63);
+    }
+
+    public void a(int i, int j, ChunkSnapshot chunksnapshot) {
+        byte b0 = 4;
+        int k = this.n.K() / 2 + 1;
+        int l = b0 + 1;
+        byte b1 = 17;
+        int i1 = b0 + 1;
+
+        this.t = this.a(this.t, i * b0, 0, j * b0, l, b1, i1);
+
+        for (int j1 = 0; j1 < b0; ++j1) {
+            for (int k1 = 0; k1 < b0; ++k1) {
+                for (int l1 = 0; l1 < 16; ++l1) {
+                    double d0 = 0.125D;
+                    double d1 = this.t[((j1 + 0) * i1 + k1 + 0) * b1 + l1 + 0];
+                    double d2 = this.t[((j1 + 0) * i1 + k1 + 1) * b1 + l1 + 0];
+                    double d3 = this.t[((j1 + 1) * i1 + k1 + 0) * b1 + l1 + 0];
+                    double d4 = this.t[((j1 + 1) * i1 + k1 + 1) * b1 + l1 + 0];
+                    double d5 = (this.t[((j1 + 0) * i1 + k1 + 0) * b1 + l1 + 1] - d1) * d0;
+                    double d6 = (this.t[((j1 + 0) * i1 + k1 + 1) * b1 + l1 + 1] - d2) * d0;
+                    double d7 = (this.t[((j1 + 1) * i1 + k1 + 0) * b1 + l1 + 1] - d3) * d0;
+                    double d8 = (this.t[((j1 + 1) * i1 + k1 + 1) * b1 + l1 + 1] - d4) * d0;
+
+                    for (int i2 = 0; i2 < 8; ++i2) {
+                        double d9 = 0.25D;
+                        double d10 = d1;
+                        double d11 = d2;
+                        double d12 = (d3 - d1) * d9;
+                        double d13 = (d4 - d2) * d9;
+
+                        for (int j2 = 0; j2 < 4; ++j2) {
+                            double d14 = 0.25D;
+                            double d15 = d10;
+                            double d16 = (d11 - d10) * d14;
+
+                            for (int k2 = 0; k2 < 4; ++k2) {
+                                IBlockData iblockdata = null;
+
+                                if (l1 * 8 + i2 < k) {
+                                    iblockdata = ChunkProviderHell.d;
+                                }
+
+                                if (d15 > 0.0D) {
+                                    iblockdata = ChunkProviderHell.b;
+                                }
+
+                                int l2 = j2 + j1 * 4;
+                                int i3 = i2 + l1 * 8;
+                                int j3 = k2 + k1 * 4;
+
+                                chunksnapshot.a(l2, i3, j3, iblockdata);
+                                d15 += d16;
+                            }
+
+                            d10 += d12;
+                            d11 += d13;
+                        }
+
+                        d1 += d5;
+                        d2 += d6;
+                        d3 += d7;
+                        d4 += d8;
+                    }
+                }
+            }
+        }
+
+    }
+
+    public void b(int i, int j, ChunkSnapshot chunksnapshot) {
+        int k = this.n.K() + 1;
+        double d0 = 0.03125D;
+
+        this.q = this.x.a(this.q, i * 16, j * 16, 0, 16, 16, 1, d0, d0, 1.0D);
+        this.r = this.x.a(this.r, i * 16, 109, j * 16, 16, 1, 16, d0, 1.0D, d0);
+        this.s = this.y.a(this.s, i * 16, j * 16, 0, 16, 16, 1, d0 * 2.0D, d0 * 2.0D, d0 * 2.0D);
+
+        for (int l = 0; l < 16; ++l) {
+            for (int i1 = 0; i1 < 16; ++i1) {
+                boolean flag = this.q[l + i1 * 16] + this.p.nextDouble() * 0.2D > 0.0D;
+                boolean flag1 = this.r[l + i1 * 16] + this.p.nextDouble() * 0.2D > 0.0D;
+                int j1 = (int) (this.s[l + i1 * 16] / 3.0D + 3.0D + this.p.nextDouble() * 0.25D);
+                int k1 = -1;
+                IBlockData iblockdata = ChunkProviderHell.b;
+                IBlockData iblockdata1 = ChunkProviderHell.b;
+
+                for (int l1 = 127; l1 >= 0; --l1) {
+                    if (l1 < 127 - this.p.nextInt(5) && l1 > this.p.nextInt(5)) {
+                        IBlockData iblockdata2 = chunksnapshot.a(i1, l1, l);
+
+                        if (iblockdata2.getBlock() != null && iblockdata2.getMaterial() != Material.AIR) {
+                            if (iblockdata2.getBlock() == Blocks.NETHERRACK) {
+                                if (k1 == -1) {
+                                    if (j1 <= 0) {
+                                        iblockdata = ChunkProviderHell.a;
+                                        iblockdata1 = ChunkProviderHell.b;
+                                    } else if (l1 >= k - 4 && l1 <= k + 1) {
+                                        iblockdata = ChunkProviderHell.b;
+                                        iblockdata1 = ChunkProviderHell.b;
+                                        if (flag1) {
+                                            iblockdata = ChunkProviderHell.e;
+                                            iblockdata1 = ChunkProviderHell.b;
+                                        }
+
+                                        if (flag) {
+                                            iblockdata = ChunkProviderHell.f;
+                                            iblockdata1 = ChunkProviderHell.f;
+                                        }
+                                    }
+
+                                    if (l1 < k && (iblockdata == null || iblockdata.getMaterial() == Material.AIR)) {
+                                        iblockdata = ChunkProviderHell.d;
+                                    }
+
+                                    k1 = j1;
+                                    if (l1 >= k - 1) {
+                                        chunksnapshot.a(i1, l1, l, iblockdata);
+                                    } else {
+                                        chunksnapshot.a(i1, l1, l, iblockdata1);
+                                    }
+                                } else if (k1 > 0) {
+                                    --k1;
+                                    chunksnapshot.a(i1, l1, l, iblockdata1);
+                                }
+                            }
+                        } else {
+                            k1 = -1;
+                        }
+                    } else {
+                        chunksnapshot.a(i1, l1, l, ChunkProviderHell.c);
+                    }
+                }
+            }
+        }
+
+    }
+
+    public Chunk getOrCreateChunk(int i, int j) {
+        this.p.setSeed((long) i * 341873128712L + (long) j * 132897987541L);
+        ChunkSnapshot chunksnapshot = new ChunkSnapshot();
+
+        this.a(i, j, chunksnapshot);
+        this.b(i, j, chunksnapshot);
+        this.I.a(this.n, i, j, chunksnapshot);
+        if (this.o) {
+            this.H.a(this.n, i, j, chunksnapshot);
+        }
+
+        Chunk chunk = new Chunk(this.n, chunksnapshot, i, j);
+        BiomeBase[] abiomebase = this.n.getWorldChunkManager().getBiomeBlock((BiomeBase[]) null, i * 16, j * 16, 16, 16);
+        byte[] abyte = chunk.getBiomeIndex();
+
+        for (int k = 0; k < abyte.length; ++k) {
+            abyte[k] = (byte) BiomeBase.a(abiomebase[k]);
+        }
+
+        chunk.m();
+        return chunk;
+    }
+
+    private double[] a(double[] adouble, int i, int j, int k, int l, int i1, int j1) {
+        if (adouble == null) {
+            adouble = new double[l * i1 * j1];
+        }
+
+        double d0 = 684.412D;
+        double d1 = 2053.236D;
+
+        this.l = this.g.a(this.l, i, j, k, l, 1, j1, 1.0D, 0.0D, 1.0D);
+        this.m = this.h.a(this.m, i, j, k, l, 1, j1, 100.0D, 0.0D, 100.0D);
+        this.i = this.w.a(this.i, i, j, k, l, i1, j1, d0 / 80.0D, d1 / 60.0D, d0 / 80.0D);
+        this.j = this.u.a(this.j, i, j, k, l, i1, j1, d0, d1, d0);
+        this.k = this.v.a(this.k, i, j, k, l, i1, j1, d0, d1, d0);
+        int k1 = 0;
+        double[] adouble1 = new double[i1];
+
+        int l1;
+
+        for (l1 = 0; l1 < i1; ++l1) {
+            adouble1[l1] = Math.cos((double) l1 * 3.141592653589793D * 6.0D / (double) i1) * 2.0D;
+            double d2 = (double) l1;
+
+            if (l1 > i1 / 2) {
+                d2 = (double) (i1 - 1 - l1);
+            }
+
+            if (d2 < 4.0D) {
+                d2 = 4.0D - d2;
+                adouble1[l1] -= d2 * d2 * d2 * 10.0D;
+            }
+        }
+
+        for (l1 = 0; l1 < l; ++l1) {
+            for (int i2 = 0; i2 < j1; ++i2) {
+                double d3 = 0.0D;
+
+                for (int j2 = 0; j2 < i1; ++j2) {
+                    double d4 = 0.0D;
+                    double d5 = adouble1[j2];
+                    double d6 = this.j[k1] / 512.0D;
+                    double d7 = this.k[k1] / 512.0D;
+                    double d8 = (this.i[k1] / 10.0D + 1.0D) / 2.0D;
+
+                    if (d8 < 0.0D) {
+                        d4 = d6;
+                    } else if (d8 > 1.0D) {
+                        d4 = d7;
+                    } else {
+                        d4 = d6 + (d7 - d6) * d8;
+                    }
+
+                    d4 -= d5;
+                    double d9;
+
+                    if (j2 > i1 - 4) {
+                        d9 = (double) ((float) (j2 - (i1 - 4)) / 3.0F);
+                        d4 = d4 * (1.0D - d9) + -10.0D * d9;
+                    }
+
+                    if ((double) j2 < d3) {
+                        d9 = (d3 - (double) j2) / 4.0D;
+                        d9 = MathHelper.a(d9, 0.0D, 1.0D);
+                        d4 = d4 * (1.0D - d9) + -10.0D * d9;
+                    }
+
+                    adouble[k1] = d4;
+                    ++k1;
+                }
+            }
+        }
+
+        return adouble;
+    }
+
+    public void recreateStructures(int i, int j) {
+        BlockFalling.instaFall = true;
+        BlockPosition blockposition = new BlockPosition(i * 16, 0, j * 16);
+        ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
+
+        this.H.a(this.n, this.p, chunkcoordintpair);
+
+        int k;
+
+        for (k = 0; k < 8; ++k) {
+            this.E.generate(this.n, this.p, blockposition.a(this.p.nextInt(16) + 8, this.p.nextInt(120) + 4, this.p.nextInt(16) + 8));
+        }
+
+        for (k = 0; k < this.p.nextInt(this.p.nextInt(10) + 1) + 1; ++k) {
+            this.z.generate(this.n, this.p, blockposition.a(this.p.nextInt(16) + 8, this.p.nextInt(120) + 4, this.p.nextInt(16) + 8));
+        }
+
+        for (k = 0; k < this.p.nextInt(this.p.nextInt(10) + 1); ++k) {
+            this.A.generate(this.n, this.p, blockposition.a(this.p.nextInt(16) + 8, this.p.nextInt(120) + 4, this.p.nextInt(16) + 8));
+        }
+
+        for (k = 0; k < 10; ++k) {
+            this.B.generate(this.n, this.p, blockposition.a(this.p.nextInt(16) + 8, this.p.nextInt(128), this.p.nextInt(16) + 8));
+        }
+
+        if (this.p.nextBoolean()) {
+            this.F.generate(this.n, this.p, blockposition.a(this.p.nextInt(16) + 8, this.p.nextInt(128), this.p.nextInt(16) + 8));
+        }
+
+        if (this.p.nextBoolean()) {
+            this.G.generate(this.n, this.p, blockposition.a(this.p.nextInt(16) + 8, this.p.nextInt(128), this.p.nextInt(16) + 8));
+        }
+
+        for (k = 0; k < 16; ++k) {
+            this.C.generate(this.n, this.p, blockposition.a(this.p.nextInt(16), this.p.nextInt(108) + 10, this.p.nextInt(16)));
+        }
+
+        for (k = 0; k < 16; ++k) {
+            this.D.generate(this.n, this.p, blockposition.a(this.p.nextInt(16), this.p.nextInt(108) + 10, this.p.nextInt(16)));
+        }
+
+        BlockFalling.instaFall = false;
+    }
+
+    public boolean a(Chunk chunk, int i, int j) {
+        return false;
+    }
+
+    public List<BiomeBase.BiomeMeta> getMobsFor(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
+        if (enumcreaturetype == EnumCreatureType.MONSTER) {
+            if (this.H.b(blockposition)) {
+                return this.H.b();
+            }
+
+            if (this.H.b(this.n, blockposition) && this.n.getType(blockposition.down()).getBlock() == Blocks.NETHER_BRICK) {
+                return this.H.b();
+            }
+        }
+
+        BiomeBase biomebase = this.n.getBiome(blockposition);
+
+        return biomebase.getMobs(enumcreaturetype);
+    }
+
+    public BlockPosition findNearestMapFeature(World world, String s, BlockPosition blockposition) {
+        return null;
+    }
+
+    public void recreateStructures(Chunk chunk, int i, int j) {
+        this.H.a(this.n, i, j, (ChunkSnapshot) null);
+    }
+}
diff --git a/src/main/java/net/minecraft/server/CommandScoreboard.java b/src/main/java/net/minecraft/server/CommandScoreboard.java
new file mode 100644
index 0000000..871535c
--- /dev/null
+++ b/src/main/java/net/minecraft/server/CommandScoreboard.java
@@ -0,0 +1,1088 @@
+package net.minecraft.server;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CommandScoreboard extends CommandAbstract {
+    public int compareTo(ICommand compare) {return getCommand().compareTo(compare.getCommand());} // Paper
+    public CommandScoreboard() {}
+
+    public String getCommand() {
+        return "scoreboard";
+    }
+
+    public int a() {
+        return 2;
+    }
+
+    public String getUsage(ICommandListener icommandlistener) {
+        return "commands.scoreboard.usage";
+    }
+
+    public void execute(MinecraftServer minecraftserver, ICommandListener icommandlistener, String[] astring) throws CommandException {
+        if (!this.b(minecraftserver, icommandlistener, astring)) {
+            if (astring.length < 1) {
+                throw new ExceptionUsage("commands.scoreboard.usage", new Object[0]);
+            } else {
+                if (astring[0].equalsIgnoreCase("objectives")) {
+                    if (astring.length == 1) {
+                        throw new ExceptionUsage("commands.scoreboard.objectives.usage", new Object[0]);
+                    }
+
+                    if (astring[1].equalsIgnoreCase("list")) {
+                        this.a(icommandlistener, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("add")) {
+                        if (astring.length < 4) {
+                            throw new ExceptionUsage("commands.scoreboard.objectives.add.usage", new Object[0]);
+                        }
+
+                        this.a(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("remove")) {
+                        if (astring.length != 3) {
+                            throw new ExceptionUsage("commands.scoreboard.objectives.remove.usage", new Object[0]);
+                        }
+
+                        this.a(icommandlistener, astring[2], minecraftserver);
+                    } else {
+                        if (!astring[1].equalsIgnoreCase("setdisplay")) {
+                            throw new ExceptionUsage("commands.scoreboard.objectives.usage", new Object[0]);
+                        }
+
+                        if (astring.length != 3 && astring.length != 4) {
+                            throw new ExceptionUsage("commands.scoreboard.objectives.setdisplay.usage", new Object[0]);
+                        }
+
+                        this.i(icommandlistener, astring, 2, minecraftserver);
+                    }
+                } else if (astring[0].equalsIgnoreCase("players")) {
+                    if (astring.length == 1) {
+                        throw new ExceptionUsage("commands.scoreboard.players.usage", new Object[0]);
+                    }
+
+                    if (astring[1].equalsIgnoreCase("list")) {
+                        if (astring.length > 3) {
+                            throw new ExceptionUsage("commands.scoreboard.players.list.usage", new Object[0]);
+                        }
+
+                        this.j(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("add")) {
+                        if (astring.length < 5) {
+                            throw new ExceptionUsage("commands.scoreboard.players.add.usage", new Object[0]);
+                        }
+
+                        this.k(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("remove")) {
+                        if (astring.length < 5) {
+                            throw new ExceptionUsage("commands.scoreboard.players.remove.usage", new Object[0]);
+                        }
+
+                        this.k(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("set")) {
+                        if (astring.length < 5) {
+                            throw new ExceptionUsage("commands.scoreboard.players.set.usage", new Object[0]);
+                        }
+
+                        this.k(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("reset")) {
+                        if (astring.length != 3 && astring.length != 4) {
+                            throw new ExceptionUsage("commands.scoreboard.players.reset.usage", new Object[0]);
+                        }
+
+                        this.l(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("enable")) {
+                        if (astring.length != 4) {
+                            throw new ExceptionUsage("commands.scoreboard.players.enable.usage", new Object[0]);
+                        }
+
+                        this.m(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("test")) {
+                        if (astring.length != 5 && astring.length != 6) {
+                            throw new ExceptionUsage("commands.scoreboard.players.test.usage", new Object[0]);
+                        }
+
+                        this.n(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("operation")) {
+                        if (astring.length != 7) {
+                            throw new ExceptionUsage("commands.scoreboard.players.operation.usage", new Object[0]);
+                        }
+
+                        this.o(icommandlistener, astring, 2, minecraftserver);
+                    } else {
+                        if (!astring[1].equalsIgnoreCase("tag")) {
+                            throw new ExceptionUsage("commands.scoreboard.players.usage", new Object[0]);
+                        }
+
+                        if (astring.length < 4) {
+                            throw new ExceptionUsage("commands.scoreboard.players.tag.usage", new Object[0]);
+                        }
+
+                        this.a(minecraftserver, icommandlistener, astring, 2);
+                    }
+                } else {
+                    if (!astring[0].equalsIgnoreCase("teams")) {
+                        throw new ExceptionUsage("commands.scoreboard.usage", new Object[0]);
+                    }
+
+                    if (astring.length == 1) {
+                        throw new ExceptionUsage("commands.scoreboard.teams.usage", new Object[0]);
+                    }
+
+                    if (astring[1].equalsIgnoreCase("list")) {
+                        if (astring.length > 3) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.list.usage", new Object[0]);
+                        }
+
+                        this.e(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("add")) {
+                        if (astring.length < 3) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.add.usage", new Object[0]);
+                        }
+
+                        this.b(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("remove")) {
+                        if (astring.length != 3) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.remove.usage", new Object[0]);
+                        }
+
+                        this.d(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("empty")) {
+                        if (astring.length != 3) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.empty.usage", new Object[0]);
+                        }
+
+                        this.h(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("join")) {
+                        if (astring.length < 4 && (astring.length != 3 || !(icommandlistener instanceof EntityHuman))) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.join.usage", new Object[0]);
+                        }
+
+                        this.f(icommandlistener, astring, 2, minecraftserver);
+                    } else if (astring[1].equalsIgnoreCase("leave")) {
+                        if (astring.length < 3 && !(icommandlistener instanceof EntityHuman)) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.leave.usage", new Object[0]);
+                        }
+
+                        this.g(icommandlistener, astring, 2, minecraftserver);
+                    } else {
+                        if (!astring[1].equalsIgnoreCase("option")) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.usage", new Object[0]);
+                        }
+
+                        if (astring.length != 4 && astring.length != 5) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.option.usage", new Object[0]);
+                        }
+
+                        this.c(icommandlistener, astring, 2, minecraftserver);
+                    }
+                }
+
+            }
+        }
+    }
+
+    private boolean b(MinecraftServer minecraftserver, ICommandListener icommandlistener, String[] astring) throws CommandException {
+        int i = -1;
+
+        for (int j = 0; j < astring.length; ++j) {
+            if (this.isListStart(astring, j) && "*".equals(astring[j])) {
+                if (i >= 0) {
+                    throw new CommandException("commands.scoreboard.noMultiWildcard", new Object[0]);
+                }
+
+                i = j;
+            }
+        }
+
+        if (i < 0) {
+            return false;
+        } else {
+            ArrayList arraylist = Lists.newArrayList(this.a(minecraftserver).getPlayers());
+            String s = astring[i];
+            ArrayList arraylist1 = Lists.newArrayList();
+            Iterator iterator = arraylist.iterator();
+
+            while (iterator.hasNext()) {
+                String s1 = (String) iterator.next();
+
+                astring[i] = s1;
+
+                try {
+                    this.execute(minecraftserver, icommandlistener, astring);
+                    arraylist1.add(s1);
+                } catch (CommandException commandexception) {
+                    ChatMessage chatmessage = new ChatMessage(commandexception.getMessage(), commandexception.getArgs());
+
+                    chatmessage.getChatModifier().setColor(EnumChatFormat.RED);
+                    icommandlistener.sendMessage(chatmessage);
+                }
+            }
+
+            astring[i] = s;
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.AFFECTED_ENTITIES, arraylist1.size());
+            if (arraylist1.isEmpty()) {
+                throw new ExceptionUsage("commands.scoreboard.allMatchesFailed", new Object[0]);
+            } else {
+                return true;
+            }
+        }
+    }
+
+    protected Scoreboard a(MinecraftServer minecraftserver) {
+        return minecraftserver.getWorldServer(0).getScoreboard();
+    }
+
+    protected ScoreboardObjective a(String s, boolean flag, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        ScoreboardObjective scoreboardobjective = scoreboard.getObjective(s);
+
+        if (scoreboardobjective == null) {
+            throw new CommandException("commands.scoreboard.objectiveNotFound", new Object[] { s});
+        } else if (flag && scoreboardobjective.getCriteria().isReadOnly()) {
+            throw new CommandException("commands.scoreboard.objectiveReadOnly", new Object[] { s});
+        } else {
+            return scoreboardobjective;
+        }
+    }
+
+    protected ScoreboardTeam a(String s, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        ScoreboardTeam scoreboardteam = scoreboard.getTeam(s);
+
+        if (scoreboardteam == null) {
+            throw new CommandException("commands.scoreboard.teamNotFound", new Object[] { s});
+        } else {
+            return scoreboardteam;
+        }
+    }
+
+    protected void a(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        String s = astring[i++];
+        String s1 = astring[i++];
+        Scoreboard scoreboard = this.a(minecraftserver);
+        IScoreboardCriteria iscoreboardcriteria = (IScoreboardCriteria) IScoreboardCriteria.criteria.get(s1);
+
+        if (iscoreboardcriteria == null) {
+            throw new ExceptionUsage("commands.scoreboard.objectives.add.wrongType", new Object[] { s1});
+        } else if (scoreboard.getObjective(s) != null) {
+            throw new CommandException("commands.scoreboard.objectives.add.alreadyExists", new Object[] { s});
+        } else if (s.length() > 16) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.objectives.add.tooLong", new Object[] { s, Integer.valueOf(16)});
+        } else if (s.isEmpty()) {
+            throw new ExceptionUsage("commands.scoreboard.objectives.add.usage", new Object[0]);
+        } else {
+            if (astring.length > i) {
+                String s2 = a(icommandlistener, astring, i).toPlainText();
+
+                if (s2.length() > 32) {
+                    throw new ExceptionInvalidSyntax("commands.scoreboard.objectives.add.displayTooLong", new Object[] { s2, Integer.valueOf(32)});
+                }
+
+                if (!s2.isEmpty()) {
+                    scoreboard.registerObjective(s, iscoreboardcriteria).setDisplayName(s2);
+                } else {
+                    scoreboard.registerObjective(s, iscoreboardcriteria);
+                }
+            } else {
+                scoreboard.registerObjective(s, iscoreboardcriteria);
+            }
+
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.objectives.add.success", new Object[] { s});
+        }
+    }
+
+    protected void b(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        String s = astring[i++];
+        Scoreboard scoreboard = this.a(minecraftserver);
+
+        if (scoreboard.getTeam(s) != null) {
+            throw new CommandException("commands.scoreboard.teams.add.alreadyExists", new Object[] { s});
+        } else if (s.length() > 16) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.teams.add.tooLong", new Object[] { s, Integer.valueOf(16)});
+        } else if (s.isEmpty()) {
+            throw new ExceptionUsage("commands.scoreboard.teams.add.usage", new Object[0]);
+        } else {
+            if (astring.length > i) {
+                String s1 = a(icommandlistener, astring, i).toPlainText();
+
+                if (s1.length() > 32) {
+                    throw new ExceptionInvalidSyntax("commands.scoreboard.teams.add.displayTooLong", new Object[] { s1, Integer.valueOf(32)});
+                }
+
+                if (!s1.isEmpty()) {
+                    scoreboard.createTeam(s).setDisplayName(s1);
+                } else {
+                    scoreboard.createTeam(s);
+                }
+            } else {
+                scoreboard.createTeam(s);
+            }
+
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.teams.add.success", new Object[] { s});
+        }
+    }
+
+    protected void c(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        ScoreboardTeam scoreboardteam = this.a(astring[i++], minecraftserver);
+
+        if (scoreboardteam != null) {
+            String s = astring[i++].toLowerCase();
+
+            if (!s.equalsIgnoreCase("color") && !s.equalsIgnoreCase("friendlyfire") && !s.equalsIgnoreCase("seeFriendlyInvisibles") && !s.equalsIgnoreCase("nametagVisibility") && !s.equalsIgnoreCase("deathMessageVisibility") && !s.equalsIgnoreCase("collisionRule")) {
+                throw new ExceptionUsage("commands.scoreboard.teams.option.usage", new Object[0]);
+            } else if (astring.length == 4) {
+                if (s.equalsIgnoreCase("color")) {
+                    throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a(EnumChatFormat.a(true, false))});
+                } else if (!s.equalsIgnoreCase("friendlyfire") && !s.equalsIgnoreCase("seeFriendlyInvisibles")) {
+                    if (!s.equalsIgnoreCase("nametagVisibility") && !s.equalsIgnoreCase("deathMessageVisibility")) {
+                        if (s.equalsIgnoreCase("collisionRule")) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Object[]) ScoreboardTeamBase.EnumTeamPush.a())});
+                        } else {
+                            throw new ExceptionUsage("commands.scoreboard.teams.option.usage", new Object[0]);
+                        }
+                    } else {
+                        throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Object[]) ScoreboardTeamBase.EnumNameTagVisibility.a())});
+                    }
+                } else {
+                    throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Collection) Arrays.asList(new String[] { "true", "false"}))});
+                }
+            } else {
+                String s1 = astring[i];
+
+                if (s.equalsIgnoreCase("color")) {
+                    EnumChatFormat enumchatformat = EnumChatFormat.b(s1);
+
+                    if (enumchatformat == null || enumchatformat.isFormat()) {
+                        throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a(EnumChatFormat.a(true, false))});
+                    }
+
+                    scoreboardteam.a(enumchatformat);
+                    scoreboardteam.setPrefix(enumchatformat.toString());
+                    scoreboardteam.setSuffix(EnumChatFormat.RESET.toString());
+                } else if (s.equalsIgnoreCase("friendlyfire")) {
+                    if (!s1.equalsIgnoreCase("true") && !s1.equalsIgnoreCase("false")) {
+                        throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Collection) Arrays.asList(new String[] { "true", "false"}))});
+                    }
+
+                    scoreboardteam.setAllowFriendlyFire(s1.equalsIgnoreCase("true"));
+                } else if (s.equalsIgnoreCase("seeFriendlyInvisibles")) {
+                    if (!s1.equalsIgnoreCase("true") && !s1.equalsIgnoreCase("false")) {
+                        throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Collection) Arrays.asList(new String[] { "true", "false"}))});
+                    }
+
+                    scoreboardteam.setCanSeeFriendlyInvisibles(s1.equalsIgnoreCase("true"));
+                } else {
+                    ScoreboardTeamBase.EnumNameTagVisibility scoreboardteambase_enumnametagvisibility;
+
+                    if (s.equalsIgnoreCase("nametagVisibility")) {
+                        scoreboardteambase_enumnametagvisibility = ScoreboardTeamBase.EnumNameTagVisibility.a(s1);
+                        if (scoreboardteambase_enumnametagvisibility == null) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Object[]) ScoreboardTeamBase.EnumNameTagVisibility.a())});
+                        }
+
+                        scoreboardteam.setNameTagVisibility(scoreboardteambase_enumnametagvisibility);
+                    } else if (s.equalsIgnoreCase("deathMessageVisibility")) {
+                        scoreboardteambase_enumnametagvisibility = ScoreboardTeamBase.EnumNameTagVisibility.a(s1);
+                        if (scoreboardteambase_enumnametagvisibility == null) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Object[]) ScoreboardTeamBase.EnumNameTagVisibility.a())});
+                        }
+
+                        scoreboardteam.b(scoreboardteambase_enumnametagvisibility);
+                    } else if (s.equalsIgnoreCase("collisionRule")) {
+                        ScoreboardTeamBase.EnumTeamPush scoreboardteambase_enumteampush = ScoreboardTeamBase.EnumTeamPush.a(s1);
+
+                        if (scoreboardteambase_enumteampush == null) {
+                            throw new ExceptionUsage("commands.scoreboard.teams.option.noValue", new Object[] { s, a((Object[]) ScoreboardTeamBase.EnumTeamPush.a())});
+                        }
+
+                        scoreboardteam.a(scoreboardteambase_enumteampush);
+                    }
+                }
+
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.teams.option.success", new Object[] { s, scoreboardteam.getName(), s1});
+            }
+        }
+    }
+
+    protected void d(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        ScoreboardTeam scoreboardteam = this.a(astring[i], minecraftserver);
+
+        if (scoreboardteam != null) {
+            scoreboard.removeTeam(scoreboardteam);
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.teams.remove.success", new Object[] { scoreboardteam.getName()});
+        }
+    }
+
+    protected void e(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+
+        if (astring.length > i) {
+            ScoreboardTeam scoreboardteam = this.a(astring[i], minecraftserver);
+
+            if (scoreboardteam == null) {
+                return;
+            }
+
+            Collection collection = scoreboardteam.getPlayerNameSet();
+
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.QUERY_RESULT, collection.size());
+            if (collection.isEmpty()) {
+                throw new CommandException("commands.scoreboard.teams.list.player.empty", new Object[] { scoreboardteam.getName()});
+            }
+
+            ChatMessage chatmessage = new ChatMessage("commands.scoreboard.teams.list.player.count", new Object[] { Integer.valueOf(collection.size()), scoreboardteam.getName()});
+
+            chatmessage.getChatModifier().setColor(EnumChatFormat.DARK_GREEN);
+            icommandlistener.sendMessage(chatmessage);
+            icommandlistener.sendMessage(new ChatComponentText(a(collection.toArray())));
+        } else {
+            Collection collection1 = scoreboard.getTeams();
+
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.QUERY_RESULT, collection1.size());
+            if (collection1.isEmpty()) {
+                throw new CommandException("commands.scoreboard.teams.list.empty", new Object[0]);
+            }
+
+            ChatMessage chatmessage1 = new ChatMessage("commands.scoreboard.teams.list.count", new Object[] { Integer.valueOf(collection1.size())});
+
+            chatmessage1.getChatModifier().setColor(EnumChatFormat.DARK_GREEN);
+            icommandlistener.sendMessage(chatmessage1);
+            Iterator iterator = collection1.iterator();
+
+            while (iterator.hasNext()) {
+                ScoreboardTeam scoreboardteam1 = (ScoreboardTeam) iterator.next();
+
+                icommandlistener.sendMessage(new ChatMessage("commands.scoreboard.teams.list.entry", new Object[] { scoreboardteam1.getName(), scoreboardteam1.getDisplayName(), Integer.valueOf(scoreboardteam1.getPlayerNameSet().size())}));
+            }
+        }
+
+    }
+
+    protected void f(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        String s = astring[i++];
+        HashSet hashset = Sets.newHashSet();
+        HashSet hashset1 = Sets.newHashSet();
+        String s1;
+
+        if (icommandlistener instanceof EntityHuman && i == astring.length) {
+            s1 = a(icommandlistener).getName();
+            if (scoreboard.addPlayerToTeam(s1, s)) {
+                hashset.add(s1);
+            } else {
+                hashset1.add(s1);
+            }
+        } else {
+            while (i < astring.length) {
+                s1 = astring[i++];
+                if (s1.startsWith("@")) {
+                    List list = c(minecraftserver, icommandlistener, s1);
+                    Iterator iterator = list.iterator();
+
+                    while (iterator.hasNext()) {
+                        Entity entity = (Entity) iterator.next();
+                        String s2 = e(minecraftserver, icommandlistener, entity.getUniqueID().toString());
+
+                        if (scoreboard.addPlayerToTeam(s2, s)) {
+                            hashset.add(s2);
+                        } else {
+                            hashset1.add(s2);
+                        }
+                    }
+                } else {
+                    String s3 = e(minecraftserver, icommandlistener, s1);
+
+                    if (scoreboard.addPlayerToTeam(s3, s)) {
+                        hashset.add(s3);
+                    } else {
+                        hashset1.add(s3);
+                    }
+                }
+            }
+        }
+
+        if (!hashset.isEmpty()) {
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.AFFECTED_ENTITIES, hashset.size());
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.teams.join.success", new Object[] { Integer.valueOf(hashset.size()), s, a(hashset.toArray(new String[hashset.size()]))});
+        }
+
+        if (!hashset1.isEmpty()) {
+            throw new CommandException("commands.scoreboard.teams.join.failure", new Object[] { Integer.valueOf(hashset1.size()), s, a(hashset1.toArray(new String[hashset1.size()]))});
+        }
+    }
+
+    protected void g(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        HashSet hashset = Sets.newHashSet();
+        HashSet hashset1 = Sets.newHashSet();
+        String s;
+
+        if (icommandlistener instanceof EntityHuman && i == astring.length) {
+            s = a(icommandlistener).getName();
+            if (scoreboard.removePlayerFromTeam(s)) {
+                hashset.add(s);
+            } else {
+                hashset1.add(s);
+            }
+        } else {
+            while (i < astring.length) {
+                s = astring[i++];
+                if (s.startsWith("@")) {
+                    List list = c(minecraftserver, icommandlistener, s);
+                    Iterator iterator = list.iterator();
+
+                    while (iterator.hasNext()) {
+                        Entity entity = (Entity) iterator.next();
+                        String s1 = e(minecraftserver, icommandlistener, entity.getUniqueID().toString());
+
+                        if (scoreboard.removePlayerFromTeam(s1)) {
+                            hashset.add(s1);
+                        } else {
+                            hashset1.add(s1);
+                        }
+                    }
+                } else {
+                    String s2 = e(minecraftserver, icommandlistener, s);
+
+                    if (scoreboard.removePlayerFromTeam(s2)) {
+                        hashset.add(s2);
+                    } else {
+                        hashset1.add(s2);
+                    }
+                }
+            }
+        }
+
+        if (!hashset.isEmpty()) {
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.AFFECTED_ENTITIES, hashset.size());
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.teams.leave.success", new Object[] { Integer.valueOf(hashset.size()), a(hashset.toArray(new String[hashset.size()]))});
+        }
+
+        if (!hashset1.isEmpty()) {
+            throw new CommandException("commands.scoreboard.teams.leave.failure", new Object[] { Integer.valueOf(hashset1.size()), a(hashset1.toArray(new String[hashset1.size()]))});
+        }
+    }
+
+    protected void h(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        ScoreboardTeam scoreboardteam = this.a(astring[i], minecraftserver);
+
+        if (scoreboardteam != null) {
+            ArrayList arraylist = Lists.newArrayList(scoreboardteam.getPlayerNameSet());
+
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.AFFECTED_ENTITIES, arraylist.size());
+            if (arraylist.isEmpty()) {
+                throw new CommandException("commands.scoreboard.teams.empty.alreadyEmpty", new Object[] { scoreboardteam.getName()});
+            } else {
+                Iterator iterator = arraylist.iterator();
+
+                while (iterator.hasNext()) {
+                    String s = (String) iterator.next();
+
+                    scoreboard.removePlayerFromTeam(s, scoreboardteam);
+                }
+
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.teams.empty.success", new Object[] { Integer.valueOf(arraylist.size()), scoreboardteam.getName()});
+            }
+        }
+    }
+
+    protected void a(ICommandListener icommandlistener, String s, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        ScoreboardObjective scoreboardobjective = this.a(s, false, minecraftserver);
+
+        scoreboard.unregisterObjective(scoreboardobjective);
+        a(icommandlistener, (ICommand) this, "commands.scoreboard.objectives.remove.success", new Object[] { s});
+    }
+
+    protected void a(ICommandListener icommandlistener, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        Collection collection = scoreboard.getObjectives();
+
+        if (collection.isEmpty()) {
+            throw new CommandException("commands.scoreboard.objectives.list.empty", new Object[0]);
+        } else {
+            ChatMessage chatmessage = new ChatMessage("commands.scoreboard.objectives.list.count", new Object[] { Integer.valueOf(collection.size())});
+
+            chatmessage.getChatModifier().setColor(EnumChatFormat.DARK_GREEN);
+            icommandlistener.sendMessage(chatmessage);
+            Iterator iterator = collection.iterator();
+
+            while (iterator.hasNext()) {
+                ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next();
+
+                icommandlistener.sendMessage(new ChatMessage("commands.scoreboard.objectives.list.entry", new Object[] { scoreboardobjective.getName(), scoreboardobjective.getDisplayName(), scoreboardobjective.getCriteria().getName()}));
+            }
+
+        }
+    }
+
+    protected void i(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        String s = astring[i++];
+        int j = Scoreboard.getSlotForName(s);
+        ScoreboardObjective scoreboardobjective = null;
+
+        if (astring.length == 4) {
+            scoreboardobjective = this.a(astring[i], false, minecraftserver);
+        }
+
+        if (j < 0) {
+            throw new CommandException("commands.scoreboard.objectives.setdisplay.invalidSlot", new Object[] { s});
+        } else {
+            scoreboard.setDisplaySlot(j, scoreboardobjective);
+            if (scoreboardobjective != null) {
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.objectives.setdisplay.successSet", new Object[] { Scoreboard.getSlotName(j), scoreboardobjective.getName()});
+            } else {
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.objectives.setdisplay.successCleared", new Object[] { Scoreboard.getSlotName(j)});
+            }
+
+        }
+    }
+
+    protected void j(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+
+        if (astring.length > i) {
+            String s = e(minecraftserver, icommandlistener, astring[i]);
+            Map map = scoreboard.getPlayerObjectives(s);
+
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.QUERY_RESULT, map.size());
+            if (map.isEmpty()) {
+                throw new CommandException("commands.scoreboard.players.list.player.empty", new Object[] { s});
+            }
+
+            ChatMessage chatmessage = new ChatMessage("commands.scoreboard.players.list.player.count", new Object[] { Integer.valueOf(map.size()), s});
+
+            chatmessage.getChatModifier().setColor(EnumChatFormat.DARK_GREEN);
+            icommandlistener.sendMessage(chatmessage);
+            Iterator iterator = map.values().iterator();
+
+            while (iterator.hasNext()) {
+                ScoreboardScore scoreboardscore = (ScoreboardScore) iterator.next();
+
+                icommandlistener.sendMessage(new ChatMessage("commands.scoreboard.players.list.player.entry", new Object[] { Integer.valueOf(scoreboardscore.getScore()), scoreboardscore.getObjective().getDisplayName(), scoreboardscore.getObjective().getName()}));
+            }
+        } else {
+            Collection collection = scoreboard.getPlayers();
+
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.QUERY_RESULT, collection.size());
+            if (collection.isEmpty()) {
+                throw new CommandException("commands.scoreboard.players.list.empty", new Object[0]);
+            }
+
+            ChatMessage chatmessage1 = new ChatMessage("commands.scoreboard.players.list.count", new Object[] { Integer.valueOf(collection.size())});
+
+            chatmessage1.getChatModifier().setColor(EnumChatFormat.DARK_GREEN);
+            icommandlistener.sendMessage(chatmessage1);
+            icommandlistener.sendMessage(new ChatComponentText(a(collection.toArray())));
+        }
+
+    }
+
+    protected void k(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        String s = astring[i - 1];
+        int j = i;
+        String s1 = e(minecraftserver, icommandlistener, astring[i++]);
+
+        if (s1.length() > 40) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.players.name.tooLong", new Object[] { s1, Integer.valueOf(40)});
+        } else {
+            ScoreboardObjective scoreboardobjective = this.a(astring[i++], true, minecraftserver);
+            int k = s.equalsIgnoreCase("set") ? a(astring[i++]) : a(astring[i++], 0);
+
+            if (astring.length > i) {
+                Entity entity = b(minecraftserver, icommandlistener, astring[j]);
+
+                try {
+                    NBTTagCompound nbttagcompound = MojangsonParser.parse(a(astring, i));
+                    NBTTagCompound nbttagcompound1 = a(entity);
+
+                    if (!GameProfileSerializer.a(nbttagcompound, nbttagcompound1, true)) {
+                        throw new CommandException("commands.scoreboard.players.set.tagMismatch", new Object[] { s1});
+                    }
+                } catch (MojangsonParseException mojangsonparseexception) {
+                    throw new CommandException("commands.scoreboard.players.set.tagError", new Object[] { mojangsonparseexception.getMessage()});
+                }
+            }
+
+            Scoreboard scoreboard = this.a(minecraftserver);
+            ScoreboardScore scoreboardscore = scoreboard.getPlayerScoreForObjective(s1, scoreboardobjective);
+
+            if (s.equalsIgnoreCase("set")) {
+                scoreboardscore.setScore(k);
+            } else if (s.equalsIgnoreCase("add")) {
+                scoreboardscore.addScore(k);
+            } else {
+                scoreboardscore.removeScore(k);
+            }
+
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.players.set.success", new Object[] { scoreboardobjective.getName(), s1, Integer.valueOf(scoreboardscore.getScore())});
+        }
+    }
+
+    protected void l(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        String s = e(minecraftserver, icommandlistener, astring[i++]);
+
+        if (astring.length > i) {
+            ScoreboardObjective scoreboardobjective = this.a(astring[i++], false, minecraftserver);
+
+            scoreboard.resetPlayerScores(s, scoreboardobjective);
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.players.resetscore.success", new Object[] { scoreboardobjective.getName(), s});
+        } else {
+            scoreboard.resetPlayerScores(s, (ScoreboardObjective) null);
+            a(icommandlistener, (ICommand) this, "commands.scoreboard.players.reset.success", new Object[] { s});
+        }
+
+    }
+
+    protected void m(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        String s = d(minecraftserver, icommandlistener, astring[i++]);
+
+        if (s.length() > 40) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.players.name.tooLong", new Object[] { s, Integer.valueOf(40)});
+        } else {
+            ScoreboardObjective scoreboardobjective = this.a(astring[i], false, minecraftserver);
+
+            if (scoreboardobjective.getCriteria() != IScoreboardCriteria.c) {
+                throw new CommandException("commands.scoreboard.players.enable.noTrigger", new Object[] { scoreboardobjective.getName()});
+            } else {
+                ScoreboardScore scoreboardscore = scoreboard.getPlayerScoreForObjective(s, scoreboardobjective);
+
+                scoreboardscore.a(false);
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.players.enable.success", new Object[] { scoreboardobjective.getName(), s});
+            }
+        }
+    }
+
+    protected void n(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        String s = e(minecraftserver, icommandlistener, astring[i++]);
+
+        if (s.length() > 40) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.players.name.tooLong", new Object[] { s, Integer.valueOf(40)});
+        } else {
+            ScoreboardObjective scoreboardobjective = this.a(astring[i++], false, minecraftserver);
+
+            if (!scoreboard.b(s, scoreboardobjective)) {
+                throw new CommandException("commands.scoreboard.players.test.notFound", new Object[] { scoreboardobjective.getName(), s});
+            } else {
+                int j = astring[i].equals("*") ? Integer.MIN_VALUE : a(astring[i]);
+
+                ++i;
+                int k = i < astring.length && !astring[i].equals("*") ? a(astring[i], j) : Integer.MAX_VALUE;
+                ScoreboardScore scoreboardscore = scoreboard.getPlayerScoreForObjective(s, scoreboardobjective);
+
+                if (scoreboardscore.getScore() >= j && scoreboardscore.getScore() <= k) {
+                    a(icommandlistener, (ICommand) this, "commands.scoreboard.players.test.success", new Object[] { Integer.valueOf(scoreboardscore.getScore()), Integer.valueOf(j), Integer.valueOf(k)});
+                } else {
+                    throw new CommandException("commands.scoreboard.players.test.failed", new Object[] { Integer.valueOf(scoreboardscore.getScore()), Integer.valueOf(j), Integer.valueOf(k)});
+                }
+            }
+        }
+    }
+
+    protected void o(ICommandListener icommandlistener, String[] astring, int i, MinecraftServer minecraftserver) throws CommandException {
+        Scoreboard scoreboard = this.a(minecraftserver);
+        String s = e(minecraftserver, icommandlistener, astring[i++]);
+        ScoreboardObjective scoreboardobjective = this.a(astring[i++], true, minecraftserver);
+        String s1 = astring[i++];
+        String s2 = e(minecraftserver, icommandlistener, astring[i++]);
+        ScoreboardObjective scoreboardobjective1 = this.a(astring[i], false, minecraftserver);
+
+        if (s.length() > 40) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.players.name.tooLong", new Object[] { s, Integer.valueOf(40)});
+        } else if (s2.length() > 40) {
+            throw new ExceptionInvalidSyntax("commands.scoreboard.players.name.tooLong", new Object[] { s2, Integer.valueOf(40)});
+        } else {
+            ScoreboardScore scoreboardscore = scoreboard.getPlayerScoreForObjective(s, scoreboardobjective);
+
+            if (!scoreboard.b(s2, scoreboardobjective1)) {
+                throw new CommandException("commands.scoreboard.players.operation.notFound", new Object[] { scoreboardobjective1.getName(), s2});
+            } else {
+                ScoreboardScore scoreboardscore1 = scoreboard.getPlayerScoreForObjective(s2, scoreboardobjective1);
+
+                if (s1.equals("+=")) {
+                    scoreboardscore.setScore(scoreboardscore.getScore() + scoreboardscore1.getScore());
+                } else if (s1.equals("-=")) {
+                    scoreboardscore.setScore(scoreboardscore.getScore() - scoreboardscore1.getScore());
+                } else if (s1.equals("*=")) {
+                    scoreboardscore.setScore(scoreboardscore.getScore() * scoreboardscore1.getScore());
+                } else if (s1.equals("/=")) {
+                    if (scoreboardscore1.getScore() != 0) {
+                        scoreboardscore.setScore(scoreboardscore.getScore() / scoreboardscore1.getScore());
+                    }
+                } else if (s1.equals("%=")) {
+                    if (scoreboardscore1.getScore() != 0) {
+                        scoreboardscore.setScore(scoreboardscore.getScore() % scoreboardscore1.getScore());
+                    }
+                } else if (s1.equals("=")) {
+                    scoreboardscore.setScore(scoreboardscore1.getScore());
+                } else if (s1.equals("<")) {
+                    scoreboardscore.setScore(Math.min(scoreboardscore.getScore(), scoreboardscore1.getScore()));
+                } else if (s1.equals(">")) {
+                    scoreboardscore.setScore(Math.max(scoreboardscore.getScore(), scoreboardscore1.getScore()));
+                } else {
+                    if (!s1.equals("><")) {
+                        throw new CommandException("commands.scoreboard.players.operation.invalidOperation", new Object[] { s1});
+                    }
+
+                    int j = scoreboardscore.getScore();
+
+                    scoreboardscore.setScore(scoreboardscore1.getScore());
+                    scoreboardscore1.setScore(j);
+                }
+
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.players.operation.success", new Object[0]);
+            }
+        }
+    }
+
+    protected void a(MinecraftServer minecraftserver, ICommandListener icommandlistener, String[] astring, int i) throws CommandException {
+        String s = e(minecraftserver, icommandlistener, astring[i]);
+        Entity entity = b(minecraftserver, icommandlistener, astring[i++]);
+        String s1 = astring[i++];
+        Set set = entity.P();
+
+        if ("list".equals(s1)) {
+            if (!set.isEmpty()) {
+                ChatMessage chatmessage = new ChatMessage("commands.scoreboard.players.tag.list", new Object[] { s});
+
+                chatmessage.getChatModifier().setColor(EnumChatFormat.DARK_GREEN);
+                icommandlistener.sendMessage(chatmessage);
+                icommandlistener.sendMessage(new ChatComponentText(a(set.toArray())));
+            }
+
+            icommandlistener.a(CommandObjectiveExecutor.EnumCommandResult.QUERY_RESULT, set.size());
+        } else if (astring.length < 5) {
+            throw new ExceptionUsage("commands.scoreboard.players.tag.usage", new Object[0]);
+        } else {
+            String s2 = astring[i++];
+
+            if (astring.length > i) {
+                try {
+                    NBTTagCompound nbttagcompound = MojangsonParser.parse(a(astring, i));
+                    NBTTagCompound nbttagcompound1 = a(entity);
+
+                    if (!GameProfileSerializer.a(nbttagcompound, nbttagcompound1, true)) {
+                        throw new CommandException("commands.scoreboard.players.tag.tagMismatch", new Object[] { s});
+                    }
+                } catch (MojangsonParseException mojangsonparseexception) {
+                    throw new CommandException("commands.scoreboard.players.tag.tagError", new Object[] { mojangsonparseexception.getMessage()});
+                }
+            }
+
+            if ("add".equals(s1)) {
+                if (!entity.a(s2)) {
+                    throw new CommandException("commands.scoreboard.players.tag.tooMany", new Object[] { Integer.valueOf(1024)});
+                }
+
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.players.tag.success.add", new Object[] { s2});
+            } else {
+                if (!"remove".equals(s1)) {
+                    throw new ExceptionUsage("commands.scoreboard.players.tag.usage", new Object[0]);
+                }
+
+                if (!entity.b(s2)) {
+                    throw new CommandException("commands.scoreboard.players.tag.notFound", new Object[] { s2});
+                }
+
+                a(icommandlistener, (ICommand) this, "commands.scoreboard.players.tag.success.remove", new Object[] { s2});
+            }
+
+        }
+    }
+
+    public List<String> tabComplete(MinecraftServer minecraftserver, ICommandListener icommandlistener, String[] astring, BlockPosition blockposition) {
+        if (astring.length == 1) {
+            return a(astring, new String[] { "objectives", "players", "teams"});
+        } else {
+            if (astring[0].equalsIgnoreCase("objectives")) {
+                if (astring.length == 2) {
+                    return a(astring, new String[] { "list", "add", "remove", "setdisplay"});
+                }
+
+                if (astring[1].equalsIgnoreCase("add")) {
+                    if (astring.length == 4) {
+                        Set set = IScoreboardCriteria.criteria.keySet();
+
+                        return a(astring, (Collection) set);
+                    }
+                } else if (astring[1].equalsIgnoreCase("remove")) {
+                    if (astring.length == 3) {
+                        return a(astring, (Collection) this.a(false, minecraftserver));
+                    }
+                } else if (astring[1].equalsIgnoreCase("setdisplay")) {
+                    if (astring.length == 3) {
+                        return a(astring, Scoreboard.h());
+                    }
+
+                    if (astring.length == 4) {
+                        return a(astring, (Collection) this.a(false, minecraftserver));
+                    }
+                }
+            } else if (astring[0].equalsIgnoreCase("players")) {
+                if (astring.length == 2) {
+                    return a(astring, new String[] { "set", "add", "remove", "reset", "list", "enable", "test", "operation", "tag"});
+                }
+
+                if (!astring[1].equalsIgnoreCase("set") && !astring[1].equalsIgnoreCase("add") && !astring[1].equalsIgnoreCase("remove") && !astring[1].equalsIgnoreCase("reset")) {
+                    if (astring[1].equalsIgnoreCase("enable")) {
+                        if (astring.length == 3) {
+                            return a(astring, minecraftserver.getPlayers());
+                        }
+
+                        if (astring.length == 4) {
+                            return a(astring, (Collection) this.b(minecraftserver));
+                        }
+                    } else if (!astring[1].equalsIgnoreCase("list") && !astring[1].equalsIgnoreCase("test")) {
+                        if (astring[1].equalsIgnoreCase("operation")) {
+                            if (astring.length == 3) {
+                                return a(astring, this.a(minecraftserver).getPlayers());
+                            }
+
+                            if (astring.length == 4) {
+                                return a(astring, (Collection) this.a(true, minecraftserver));
+                            }
+
+                            if (astring.length == 5) {
+                                return a(astring, new String[] { "+=", "-=", "*=", "/=", "%=", "=", "<", ">", "><"});
+                            }
+
+                            if (astring.length == 6) {
+                                return a(astring, minecraftserver.getPlayers());
+                            }
+
+                            if (astring.length == 7) {
+                                return a(astring, (Collection) this.a(false, minecraftserver));
+                            }
+                        } else if (astring[1].equalsIgnoreCase("tag")) {
+                            if (astring.length == 3) {
+                                return a(astring, this.a(minecraftserver).getPlayers());
+                            }
+
+                            if (astring.length == 4) {
+                                return a(astring, new String[] { "add", "remove", "list"});
+                            }
+                        }
+                    } else {
+                        if (astring.length == 3) {
+                            return a(astring, this.a(minecraftserver).getPlayers());
+                        }
+
+                        if (astring.length == 4 && astring[1].equalsIgnoreCase("test")) {
+                            return a(astring, (Collection) this.a(false, minecraftserver));
+                        }
+                    }
+                } else {
+                    if (astring.length == 3) {
+                        return a(astring, minecraftserver.getPlayers());
+                    }
+
+                    if (astring.length == 4) {
+                        return a(astring, (Collection) this.a(true, minecraftserver));
+                    }
+                }
+            } else if (astring[0].equalsIgnoreCase("teams")) {
+                if (astring.length == 2) {
+                    return a(astring, new String[] { "add", "remove", "join", "leave", "empty", "list", "option"});
+                }
+
+                if (astring[1].equalsIgnoreCase("join")) {
+                    if (astring.length == 3) {
+                        return a(astring, this.a(minecraftserver).getTeamNames());
+                    }
+
+                    if (astring.length >= 4) {
+                        return a(astring, minecraftserver.getPlayers());
+                    }
+                } else {
+                    if (astring[1].equalsIgnoreCase("leave")) {
+                        return a(astring, minecraftserver.getPlayers());
+                    }
+
+                    if (!astring[1].equalsIgnoreCase("empty") && !astring[1].equalsIgnoreCase("list") && !astring[1].equalsIgnoreCase("remove")) {
+                        if (astring[1].equalsIgnoreCase("option")) {
+                            if (astring.length == 3) {
+                                return a(astring, this.a(minecraftserver).getTeamNames());
+                            }
+
+                            if (astring.length == 4) {
+                                return a(astring, new String[] { "color", "friendlyfire", "seeFriendlyInvisibles", "nametagVisibility", "deathMessageVisibility", "collisionRule"});
+                            }
+
+                            if (astring.length == 5) {
+                                if (astring[3].equalsIgnoreCase("color")) {
+                                    return a(astring, EnumChatFormat.a(true, false));
+                                }
+
+                                if (astring[3].equalsIgnoreCase("nametagVisibility") || astring[3].equalsIgnoreCase("deathMessageVisibility")) {
+                                    return a(astring, ScoreboardTeamBase.EnumNameTagVisibility.a());
+                                }
+
+                                if (astring[3].equalsIgnoreCase("collisionRule")) {
+                                    return a(astring, ScoreboardTeamBase.EnumTeamPush.a());
+                                }
+
+                                if (astring[3].equalsIgnoreCase("friendlyfire") || astring[3].equalsIgnoreCase("seeFriendlyInvisibles")) {
+                                    return a(astring, new String[] { "true", "false"});
+                                }
+                            }
+                        }
+                    } else if (astring.length == 3) {
+                        return a(astring, this.a(minecraftserver).getTeamNames());
+                    }
+                }
+            }
+
+            return Collections.emptyList();
+        }
+    }
+
+    protected List<String> a(boolean flag, MinecraftServer minecraftserver) {
+        Collection collection = this.a(minecraftserver).getObjectives();
+        ArrayList arraylist = Lists.newArrayList();
+        Iterator iterator = collection.iterator();
+
+        while (iterator.hasNext()) {
+            ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next();
+
+            if (!flag || !scoreboardobjective.getCriteria().isReadOnly()) {
+                arraylist.add(scoreboardobjective.getName());
+            }
+        }
+
+        return arraylist;
+    }
+
+    protected List<String> b(MinecraftServer minecraftserver) {
+        Collection collection = this.a(minecraftserver).getObjectives();
+        ArrayList arraylist = Lists.newArrayList();
+        Iterator iterator = collection.iterator();
+
+        while (iterator.hasNext()) {
+            ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next();
+
+            if (scoreboardobjective.getCriteria() == IScoreboardCriteria.c) {
+                arraylist.add(scoreboardobjective.getName());
+            }
+        }
+
+        return arraylist;
+    }
+
+    public boolean isListStart(String[] astring, int i) {
+        return !astring[0].equalsIgnoreCase("players") ? (astring[0].equalsIgnoreCase("teams") ? i == 2 : false) : (astring.length > 1 && astring[1].equalsIgnoreCase("operation") ? i == 2 || i == 5 : i == 2);
+    }
+}
diff --git a/src/main/java/net/minecraft/server/EULA.java b/src/main/java/net/minecraft/server/EULA.java
new file mode 100644
index 0000000..c872029
--- /dev/null
+++ b/src/main/java/net/minecraft/server/EULA.java
@@ -0,0 +1,62 @@
+package net.minecraft.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Properties;
+import org.apache.commons.io.IOUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class EULA {
+
+    private static final Logger a = LogManager.getLogger();
+    private final File b;
+    private final boolean c;
+
+    public EULA(File file) {
+        this.b = file;
+        this.c = this.a(file);
+    }
+
+    private boolean a(File file) {
+        FileInputStream fileinputstream = null;
+        boolean flag = false;
+
+        try {
+            Properties properties = new Properties();
+
+            fileinputstream = new FileInputStream(file);
+            properties.load(fileinputstream);
+            flag = Boolean.parseBoolean(properties.getProperty("eula", "false"));
+        } catch (Exception exception) {
+            EULA.a.warn("Failed to load " + file);
+            this.b();
+        } finally {
+            IOUtils.closeQuietly(fileinputstream);
+        }
+
+        return flag;
+    }
+
+    public boolean a() {
+        return this.c;
+    }
+
+    public void b() {
+        FileOutputStream fileoutputstream = null;
+
+        try {
+            Properties properties = new Properties();
+
+            fileoutputstream = new FileOutputStream(this.b);
+            properties.setProperty("eula", "false");
+            properties.store(fileoutputstream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).");
+        } catch (Exception exception) {
+            EULA.a.warn("Failed to save " + this.b, exception);
+        } finally {
+            IOUtils.closeQuietly(fileoutputstream);
+        }
+
+    }
+}
diff --git a/src/main/java/net/minecraft/server/EntitySquid.java b/src/main/java/net/minecraft/server/EntitySquid.java
new file mode 100644
index 0000000..b94444d
--- /dev/null
+++ b/src/main/java/net/minecraft/server/EntitySquid.java
@@ -0,0 +1,182 @@
+package net.minecraft.server;
+
+public class EntitySquid extends EntityWaterAnimal {
+
+    public float a;
+    public float b;
+    public float c;
+    public float bt;
+    public float bu;
+    public float bv;
+    public float bw;
+    public float bx;
+    private float by;
+    private float bz;
+    private float bA;
+    private float bB;
+    private float bC;
+    private float bD;
+
+    public EntitySquid(World world) {
+        super(world);
+        this.setSize(0.8F, 0.8F);
+        this.random.setSeed((long) (1 + this.getId()));
+        this.bz = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
+    }
+
+    protected void r() {
+        this.goalSelector.a(0, new PathfinderGoalSquid(this));
+    }
+
+    protected void initAttributes() {
+        super.initAttributes();
+        this.getAttributeInstance(GenericAttributes.maxHealth).setValue(10.0D);
+    }
+
+    public float getHeadHeight() {
+        return this.length * 0.5F;
+    }
+
+    protected SoundEffect G() {
+        return SoundEffects.fW;
+    }
+
+    protected SoundEffect bR() {
+        return SoundEffects.fY;
+    }
+
+    protected SoundEffect bS() {
+        return SoundEffects.fX;
+    }
+
+    protected float cd() {
+        return 0.4F;
+    }
+
+    protected boolean playStepSound() {
+        return false;
+    }
+
+    protected MinecraftKey J() {
+        return LootTables.af;
+    }
+
+    public boolean isInWater() {
+        return super.isInWater();
+    }
+
+    public void n() {
+        super.n();
+        this.b = this.a;
+        this.bt = this.c;
+        this.bv = this.bu;
+        this.bx = this.bw;
+        this.bu += this.bz;
+        if ((double) this.bu > 6.283185307179586D) {
+            if (this.world.isClientSide) {
+                this.bu = 6.2831855F;
+            } else {
+                this.bu = (float) ((double) this.bu - 6.283185307179586D);
+                if (this.random.nextInt(10) == 0) {
+                    this.bz = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
+                }
+
+                this.world.broadcastEntityEffect(this, (byte) 19);
+            }
+        }
+
+        if (this.inWater) {
+            float f;
+
+            if (this.bu < 3.1415927F) {
+                f = this.bu / 3.1415927F;
+                this.bw = MathHelper.sin(f * f * 3.1415927F) * 3.1415927F * 0.25F;
+                if ((double) f > 0.75D) {
+                    this.by = 1.0F;
+                    this.bA = 1.0F;
+                } else {
+                    this.bA *= 0.8F;
+                }
+            } else {
+                this.bw = 0.0F;
+                this.by *= 0.9F;
+                this.bA *= 0.99F;
+            }
+
+            if (!this.world.isClientSide) {
+                this.motX = (double) (this.bB * this.by);
+                this.motY = (double) (this.bC * this.by);
+                this.motZ = (double) (this.bD * this.by);
+            }
+
+            f = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ);
+            this.aM += (-((float) MathHelper.b(this.motX, this.motZ)) * 57.295776F - this.aM) * 0.1F;
+            this.yaw = this.aM;
+            this.c = (float) ((double) this.c + 3.141592653589793D * (double) this.bA * 1.5D);
+            this.a += (-((float) MathHelper.b((double) f, this.motY)) * 57.295776F - this.a) * 0.1F;
+        } else {
+            this.bw = MathHelper.e(MathHelper.sin(this.bu)) * 3.1415927F * 0.25F;
+            if (!this.world.isClientSide) {
+                this.motX = 0.0D;
+                this.motZ = 0.0D;
+                if (this.hasEffect(MobEffects.LEVITATION)) {
+                    this.motY += 0.05D * (double) (this.getEffect(MobEffects.LEVITATION).getAmplifier() + 1) - this.motY;
+                } else {
+                    this.motY -= 0.08D;
+                }
+
+                this.motY *= 0.9800000190734863D;
+            }
+
+            this.a = (float) ((double) this.a + (double) (-90.0F - this.a) * 0.02D);
+        }
+
+    }
+
+    public void g(float f, float f1) {
+        this.move(this.motX, this.motY, this.motZ);
+    }
+
+    public boolean cF() {
+        return this.locY > 45.0D && this.locY < (double) this.world.K() && super.cF();
+    }
+
+    public void b(float f, float f1, float f2) {
+        this.bB = f;
+        this.bC = f1;
+        this.bD = f2;
+    }
+
+    public boolean o() {
+        return this.bB != 0.0F || this.bC != 0.0F || this.bD != 0.0F;
+    }
+
+    static class PathfinderGoalSquid extends PathfinderGoal {
+
+        private EntitySquid a;
+
+        public PathfinderGoalSquid(EntitySquid entitysquid) {
+            this.a = entitysquid;
+        }
+
+        public boolean a() {
+            return true;
+        }
+
+        public void e() {
+            int i = this.a.bK();
+
+            if (i > 100) {
+                this.a.b(0.0F, 0.0F, 0.0F);
+            } else if (this.a.getRandom().nextInt(50) == 0 || !this.a.inWater || !this.a.o()) {
+                float f = this.a.getRandom().nextFloat() * 6.2831855F;
+                float f1 = MathHelper.cos(f) * 0.2F;
+                float f2 = -0.1F + this.a.getRandom().nextFloat() * 0.2F;
+                float f3 = MathHelper.sin(f) * 0.2F;
+
+                this.a.b(f1, f2, f3);
+            }
+
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/server/FileIOThread.java b/src/main/java/net/minecraft/server/FileIOThread.java
new file mode 100644
index 0000000..4733f94
--- /dev/null
+++ b/src/main/java/net/minecraft/server/FileIOThread.java
@@ -0,0 +1,75 @@
+package net.minecraft.server;
+
+import com.google.common.collect.Lists;
+import java.util.Collections;
+import java.util.List;
+
+public class FileIOThread implements Runnable {
+
+    private static final FileIOThread a = new FileIOThread();
+    private List<IAsyncChunkSaver> b = Collections.synchronizedList(Lists.newArrayList());
+    private volatile long c;
+    private volatile long d;
+    private volatile boolean e;
+
+    private FileIOThread() {
+        Thread thread = new Thread(this, "File IO Thread");
+
+        thread.setPriority(1);
+        thread.start();
+    }
+
+    public static FileIOThread a() {
+        return FileIOThread.a;
+    }
+
+    public void run() {
+        while (true) {
+            this.c();
+        }
+    }
+
+    private void c() {
+        for (int i = 0; i < this.b.size(); ++i) {
+            IAsyncChunkSaver iasyncchunksaver = (IAsyncChunkSaver) this.b.get(i);
+            boolean flag = iasyncchunksaver.c();
+
+            if (!flag) {
+                this.b.remove(i--);
+                ++this.d;
+            }
+
+            try {
+                Thread.sleep(this.e ? 0L : 10L);
+            } catch (InterruptedException interruptedexception) {
+                interruptedexception.printStackTrace();
+            }
+        }
+
+        if (this.b.isEmpty()) {
+            try {
+                Thread.sleep(25L);
+            } catch (InterruptedException interruptedexception1) {
+                interruptedexception1.printStackTrace();
+            }
+        }
+
+    }
+
+    public void a(IAsyncChunkSaver iasyncchunksaver) {
+        if (!this.b.contains(iasyncchunksaver)) {
+            ++this.c;
+            this.b.add(iasyncchunksaver);
+        }
+    }
+
+    public void b() throws InterruptedException {
+        this.e = true;
+
+        while (this.c != this.d) {
+            Thread.sleep(10L);
+        }
+
+        this.e = false;
+    }
+}
diff --git a/src/main/java/net/minecraft/server/ItemBlock.java b/src/main/java/net/minecraft/server/ItemBlock.java
new file mode 100644
index 0000000..300573a
--- /dev/null
+++ b/src/main/java/net/minecraft/server/ItemBlock.java
@@ -0,0 +1,98 @@
+package net.minecraft.server;
+
+public class ItemBlock extends Item {
+
+    protected final Block a;
+
+    public ItemBlock(Block block) {
+        this.a = block;
+    }
+
+    public ItemBlock b(String s) {
+        super.c(s);
+        return this;
+    }
+
+    public EnumInteractionResult a(ItemStack itemstack, EntityHuman entityhuman, World world, BlockPosition blockposition, EnumHand enumhand, EnumDirection enumdirection, float f, float f1, float f2) {
+        IBlockData iblockdata = world.getType(blockposition);
+        Block block = iblockdata.getBlock();
+
+        if (!block.a((IBlockAccess) world, blockposition)) {
+            blockposition = blockposition.shift(enumdirection);
+        }
+
+        if (itemstack.count != 0 && entityhuman.a(blockposition, enumdirection, itemstack) && world.a(this.a, blockposition, false, enumdirection, (Entity) null, itemstack)) {
+            int i = this.filterData(itemstack.getData());
+            IBlockData iblockdata1 = this.a.getPlacedState(world, blockposition, enumdirection, f, f1, f2, i, entityhuman);
+
+            if (world.setTypeAndData(blockposition, iblockdata1, 11)) {
+                iblockdata1 = world.getType(blockposition);
+                if (iblockdata1.getBlock() == this.a) {
+                    a(world, entityhuman, blockposition, itemstack);
+                    this.a.postPlace(world, blockposition, iblockdata1, entityhuman, itemstack);
+                }
+
+                SoundEffectType soundeffecttype = this.a.w();
+
+                world.a(entityhuman, blockposition, soundeffecttype.e(), SoundCategory.BLOCKS, (soundeffecttype.a() + 1.0F) / 2.0F, soundeffecttype.b() * 0.8F);
+                --itemstack.count;
+            }
+
+            return EnumInteractionResult.SUCCESS;
+        } else {
+            return EnumInteractionResult.FAIL;
+        }
+    }
+
+    public static boolean a(World world, EntityHuman entityhuman, BlockPosition blockposition, ItemStack itemstack) {
+        MinecraftServer minecraftserver = world.getMinecraftServer();
+
+        if (minecraftserver == null) {
+            return false;
+        } else {
+            if (itemstack.hasTag() && itemstack.getTag().hasKeyOfType("BlockEntityTag", 10)) {
+                TileEntity tileentity = world.getTileEntity(blockposition);
+
+                if (tileentity != null) {
+                    if (!world.isClientSide && tileentity.isFilteredNBT() && (entityhuman == null || !minecraftserver.getPlayerList().isOp(entityhuman.getProfile()))) {
+                        return false;
+                    }
+
+                    NBTTagCompound nbttagcompound = new NBTTagCompound();
+                    NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttagcompound.clone();
+
+                    tileentity.save(nbttagcompound);
+                    NBTTagCompound nbttagcompound2 = (NBTTagCompound) itemstack.getTag().get("BlockEntityTag");
+
+                    nbttagcompound.a(nbttagcompound2);
+                    nbttagcompound.setInt("x", blockposition.getX());
+                    nbttagcompound.setInt("y", blockposition.getY());
+                    nbttagcompound.setInt("z", blockposition.getZ());
+                    if (!nbttagcompound.equals(nbttagcompound1)) {
+                        tileentity.a(nbttagcompound);
+                        tileentity.update();
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+
+    public String f_(ItemStack itemstack) {
+        return this.a.a();
+    }
+
+    public String getName() {
+        return this.a.a();
+    }
+
+    public Block d() {
+        return this.a;
+    }
+
+    public Item c(String s) {
+        return this.b(s);
+    }
+}
diff --git a/src/main/java/net/minecraft/server/PacketPlayInResourcePackStatus.java b/src/main/java/net/minecraft/server/PacketPlayInResourcePackStatus.java
new file mode 100644
index 0000000..30ca225
--- /dev/null
+++ b/src/main/java/net/minecraft/server/PacketPlayInResourcePackStatus.java
@@ -0,0 +1,32 @@
+package net.minecraft.server;
+
+import java.io.IOException;
+
+public class PacketPlayInResourcePackStatus implements Packet<PacketListenerPlayIn> {
+
+    private String a;
+    public PacketPlayInResourcePackStatus.EnumResourcePackStatus status;
+
+    public PacketPlayInResourcePackStatus() {}
+
+    public void a(PacketDataSerializer packetdataserializer) throws IOException {
+        this.a = packetdataserializer.c(40);
+        this.status = (PacketPlayInResourcePackStatus.EnumResourcePackStatus) packetdataserializer.a(PacketPlayInResourcePackStatus.EnumResourcePackStatus.class);
+    }
+
+    public void b(PacketDataSerializer packetdataserializer) throws IOException {
+        packetdataserializer.a(this.a);
+        packetdataserializer.a((Enum) this.status);
+    }
+
+    public void a(PacketListenerPlayIn packetlistenerplayin) {
+        packetlistenerplayin.a(this);
+    }
+
+    public static enum EnumResourcePackStatus {
+
+        SUCCESSFULLY_LOADED, DECLINED, FAILED_DOWNLOAD, ACCEPTED;
+
+        private EnumResourcePackStatus() {}
+    }
+}
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalFloat.java b/src/main/java/net/minecraft/server/PathfinderGoalFloat.java
new file mode 100644
index 0000000..1a20dbf
--- /dev/null
+++ b/src/main/java/net/minecraft/server/PathfinderGoalFloat.java
@@ -0,0 +1,23 @@
+package net.minecraft.server;
+
+public class PathfinderGoalFloat extends PathfinderGoal {
+
+    private EntityInsentient a;
+
+    public PathfinderGoalFloat(EntityInsentient entityinsentient) {
+        this.a = entityinsentient;
+        this.a(4);
+        ((Navigation) entityinsentient.getNavigation()).c(true);
+    }
+
+    public boolean a() {
+        return this.a.isInWater() || this.a.an();
+    }
+
+    public void e() {
+        if (this.a.getRandom().nextFloat() < 0.8F) {
+            this.a.getControllerJump().a();
+        }
+
+    }
+}
diff --git a/src/main/java/net/minecraft/server/PersistentVillage.java b/src/main/java/net/minecraft/server/PersistentVillage.java
new file mode 100644
index 0000000..107f582
--- /dev/null
+++ b/src/main/java/net/minecraft/server/PersistentVillage.java
@@ -0,0 +1,266 @@
+package net.minecraft.server;
+
+import com.google.common.collect.Lists;
+import java.util.Iterator;
+import java.util.List;
+
+public class PersistentVillage extends PersistentBase {
+
+    private World world;
+    private final List<BlockPosition> c = Lists.newArrayList();
+    private final List<VillageDoor> d = Lists.newArrayList();
+    private final List<Village> villages = Lists.newArrayList();
+    private int time;
+
+    public PersistentVillage(String s) {
+        super(s);
+    }
+
+    public PersistentVillage(World world) {
+        super(a(world.worldProvider));
+        this.world = world;
+        this.c();
+    }
+
+    public void a(World world) {
+        this.world = world;
+        Iterator iterator = this.villages.iterator();
+
+        while (iterator.hasNext()) {
+            Village village = (Village) iterator.next();
+
+            village.a(world);
+        }
+
+    }
+
+    public void a(BlockPosition blockposition) {
+        if (this.c.size() <= 64) {
+            if (!this.e(blockposition)) {
+                this.c.add(blockposition);
+            }
+
+        }
+    }
+
+    public void tick() {
+        ++this.time;
+        Iterator iterator = this.villages.iterator();
+
+        while (iterator.hasNext()) {
+            Village village = (Village) iterator.next();
+
+            village.a(this.time);
+        }
+
+        this.e();
+        this.f();
+        this.g();
+        if (this.time % 400 == 0) {
+            this.c();
+        }
+
+    }
+
+    private void e() {
+        Iterator iterator = this.villages.iterator();
+
+        while (iterator.hasNext()) {
+            Village village = (Village) iterator.next();
+
+            if (village.g()) {
+                iterator.remove();
+                this.c();
+            }
+        }
+
+    }
+
+    public List<Village> getVillages() {
+        return this.villages;
+    }
+
+    public Village getClosestVillage(BlockPosition blockposition, int i) {
+        Village village = null;
+        double d0 = 3.4028234663852886E38D;
+        Iterator iterator = this.villages.iterator();
+
+        while (iterator.hasNext()) {
+            Village village1 = (Village) iterator.next();
+            double d1 = village1.a().k(blockposition);
+
+            if (d1 < d0) {
+                float f = (float) (i + village1.b());
+
+                if (d1 <= (double) (f * f)) {
+                    village = village1;
+                    d0 = d1;
+                }
+            }
+        }
+
+        return village;
+    }
+
+    private void f() {
+        if (!this.c.isEmpty()) {
+            this.b((BlockPosition) this.c.remove(0));
+        }
+    }
+
+    private void g() {
+        for (int i = 0; i < this.d.size(); ++i) {
+            VillageDoor villagedoor = (VillageDoor) this.d.get(i);
+            Village village = this.getClosestVillage(villagedoor.d(), 32);
+
+            if (village == null) {
+                village = new Village(this.world);
+                this.villages.add(village);
+                this.c();
+            }
+
+            village.a(villagedoor);
+        }
+
+        this.d.clear();
+    }
+
+    private void b(BlockPosition blockposition) {
+        byte b0 = 16;
+        byte b1 = 4;
+        byte b2 = 16;
+
+        for (int i = -b0; i < b0; ++i) {
+            for (int j = -b1; j < b1; ++j) {
+                for (int k = -b2; k < b2; ++k) {
+                    BlockPosition blockposition1 = blockposition.a(i, j, k);
+
+                    if (this.f(blockposition1)) {
+                        VillageDoor villagedoor = this.c(blockposition1);
+
+                        if (villagedoor == null) {
+                            this.d(blockposition1);
+                        } else {
+                            villagedoor.a(this.time);
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    private VillageDoor c(BlockPosition blockposition) {
+        Iterator iterator = this.d.iterator();
+
+        VillageDoor villagedoor;
+
+        do {
+            if (!iterator.hasNext()) {
+                iterator = this.villages.iterator();
+
+                VillageDoor villagedoor1;
+
+                do {
+                    if (!iterator.hasNext()) {
+                        return null;
+                    }
+
+                    Village village = (Village) iterator.next();
+
+                    villagedoor1 = village.e(blockposition);
+                } while (villagedoor1 == null);
+
+                return villagedoor1;
+            }
+
+            villagedoor = (VillageDoor) iterator.next();
+        } while (villagedoor.d().getX() != blockposition.getX() || villagedoor.d().getZ() != blockposition.getZ() || Math.abs(villagedoor.d().getY() - blockposition.getY()) > 1);
+
+        return villagedoor;
+    }
+
+    private void d(BlockPosition blockposition) {
+        EnumDirection enumdirection = BlockDoor.f(this.world, blockposition);
+        EnumDirection enumdirection1 = enumdirection.opposite();
+        int i = this.a(blockposition, enumdirection, 5);
+        int j = this.a(blockposition, enumdirection1, i + 1);
+
+        if (i != j) {
+            this.d.add(new VillageDoor(blockposition, i < j ? enumdirection : enumdirection1, this.time));
+        }
+
+    }
+
+    private int a(BlockPosition blockposition, EnumDirection enumdirection, int i) {
+        int j = 0;
+
+        for (int k = 1; k <= 5; ++k) {
+            if (this.world.h(blockposition.shift(enumdirection, k))) {
+                ++j;
+                if (j >= i) {
+                    return j;
+                }
+            }
+        }
+
+        return j;
+    }
+
+    private boolean e(BlockPosition blockposition) {
+        Iterator iterator = this.c.iterator();
+
+        BlockPosition blockposition1;
+
+        do {
+            if (!iterator.hasNext()) {
+                return false;
+            }
+
+            blockposition1 = (BlockPosition) iterator.next();
+        } while (!blockposition1.equals(blockposition));
+
+        return true;
+    }
+
+    private boolean f(BlockPosition blockposition) {
+        IBlockData iblockdata = this.world.getType(blockposition);
+        Block block = iblockdata.getBlock();
+
+        return block instanceof BlockDoor ? iblockdata.getMaterial() == Material.WOOD : false;
+    }
+
+    public void a(NBTTagCompound nbttagcompound) {
+        this.time = nbttagcompound.getInt("Tick");
+        NBTTagList nbttaglist = nbttagcompound.getList("Villages", 10);
+
+        for (int i = 0; i < nbttaglist.size(); ++i) {
+            NBTTagCompound nbttagcompound1 = nbttaglist.get(i);
+            Village village = new Village();
+
+            village.a(nbttagcompound1);
+            this.villages.add(village);
+        }
+
+    }
+
+    public void b(NBTTagCompound nbttagcompound) {
+        nbttagcompound.setInt("Tick", this.time);
+        NBTTagList nbttaglist = new NBTTagList();
+        Iterator iterator = this.villages.iterator();
+
+        while (iterator.hasNext()) {
+            Village village = (Village) iterator.next();
+            NBTTagCompound nbttagcompound1 = new NBTTagCompound();
+
+            village.b(nbttagcompound1);
+            nbttaglist.add(nbttagcompound1);
+        }
+
+        nbttagcompound.set("Villages", nbttaglist);
+    }
+
+    public static String a(WorldProvider worldprovider) {
+        return "villages" + worldprovider.getDimensionManager().c();
+    }
+}
diff --git a/src/main/java/net/minecraft/server/TileEntityEnderChest.java b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
new file mode 100644
index 0000000..e454622
--- /dev/null
+++ b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
@@ -0,0 +1,87 @@
+package net.minecraft.server;
+
+public class TileEntityEnderChest extends TileEntity implements ITickable {
+
+    public float a;
+    public float f;
+    public int g;
+    private int h;
+
+    public TileEntityEnderChest() {}
+
+    public void c() {
+        if (++this.h % 20 * 4 == 0) {
+            this.world.playBlockAction(this.position, Blocks.ENDER_CHEST, 1, this.g);
+        }
+
+        this.f = this.a;
+        int i = this.position.getX();
+        int j = this.position.getY();
+        int k = this.position.getZ();
+        float f = 0.1F;
+        double d0;
+
+        if (this.g > 0 && this.a == 0.0F) {
+            double d1 = (double) i + 0.5D;
+
+            d0 = (double) k + 0.5D;
+            this.world.a((EntityHuman) null, d1, (double) j + 0.5D, d0, SoundEffects.aL, SoundCategory.BLOCKS, 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F);
+        }
+
+        if (this.g == 0 && this.a > 0.0F || this.g > 0 && this.a < 1.0F) {
+            float f1 = this.a;
+
+            if (this.g > 0) {
+                this.a += f;
+            } else {
+                this.a -= f;
+            }
+
+            if (this.a > 1.0F) {
+                this.a = 1.0F;
+            }
+
+            float f2 = 0.5F;
+
+            if (this.a < f2 && f1 >= f2) {
+                d0 = (double) i + 0.5D;
+                double d2 = (double) k + 0.5D;
+
+                this.world.a((EntityHuman) null, d0, (double) j + 0.5D, d2, SoundEffects.aK, SoundCategory.BLOCKS, 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F);
+            }
+
+            if (this.a < 0.0F) {
+                this.a = 0.0F;
+            }
+        }
+
+    }
+
+    public boolean c(int i, int j) {
+        if (i == 1) {
+            this.g = j;
+            return true;
+        } else {
+            return super.c(i, j);
+        }
+    }
+
+    public void y() {
+        this.invalidateBlockCache();
+        super.y();
+    }
+
+    public void b() {
+        ++this.g;
+        this.world.playBlockAction(this.position, Blocks.ENDER_CHEST, 1, this.g);
+    }
+
+    public void d() {
+        --this.g;
+        this.world.playBlockAction(this.position, Blocks.ENDER_CHEST, 1, this.g);
+    }
+
+    public boolean a(EntityHuman entityhuman) {
+        return this.world.getTileEntity(this.position) != this ? false : entityhuman.e((double) this.position.getX() + 0.5D, (double) this.position.getY() + 0.5D, (double) this.position.getZ() + 0.5D) <= 64.0D;
+    }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/PacketPlayOutPlayerListHeaderFooter.java b/src/main/java/org/bukkit/craftbukkit/entity/PacketPlayOutPlayerListHeaderFooter.java
new file mode 100644
index 0000000..842db1d
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/entity/PacketPlayOutPlayerListHeaderFooter.java
@@ -0,0 +1,34 @@
+package org.bukkit.craftbukkit.entity;
+
+import net.minecraft.server.IChatBaseComponent;
+import net.minecraft.server.Packet;
+import net.minecraft.server.PacketDataSerializer;
+import net.minecraft.server.PacketListenerPlayOut;
+
+import java.io.IOException;
+
+public class PacketPlayOutPlayerListHeaderFooter implements Packet<PacketListenerPlayOut> {
+
+    private IChatBaseComponent a;
+    private IChatBaseComponent b;
+
+    public PacketPlayOutPlayerListHeaderFooter() {}
+
+    public PacketPlayOutPlayerListHeaderFooter(IChatBaseComponent ichatbasecomponent) {
+        this.a = ichatbasecomponent;
+    }
+
+    public void a(PacketDataSerializer packetdataserializer) throws IOException {
+        this.a = packetdataserializer.f();
+        this.b = packetdataserializer.f();
+    }
+
+    public void b(PacketDataSerializer packetdataserializer) throws IOException {
+        packetdataserializer.a(this.a);
+        packetdataserializer.a(this.b);
+    }
+
+    public void a(PacketListenerPlayOut packetlistenerplayout) {
+        packetlistenerplayout.a(this);
+    }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/PacketPlayOutTitle.java b/src/main/java/org/bukkit/craftbukkit/entity/PacketPlayOutTitle.java
new file mode 100644
index 0000000..2286c9e
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/entity/PacketPlayOutTitle.java
@@ -0,0 +1,99 @@
+package net.minecraft.server;
+
+import java.io.IOException;
+
+public class PacketPlayOutTitle implements Packet<PacketListenerPlayOut> {
+
+    private PacketPlayOutTitle.EnumTitleAction a;
+    private IChatBaseComponent b;
+    private int c;
+    private int d;
+    private int e;
+
+    public PacketPlayOutTitle() {}
+
+    public PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction packetplayouttitle_enumtitleaction, IChatBaseComponent ichatbasecomponent) {
+        this(packetplayouttitle_enumtitleaction, ichatbasecomponent, -1, -1, -1);
+    }
+
+    public PacketPlayOutTitle(int i, int j, int k) {
+        this(PacketPlayOutTitle.EnumTitleAction.TIMES, (IChatBaseComponent) null, i, j, k);
+    }
+
+    public PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction packetplayouttitle_enumtitleaction, IChatBaseComponent ichatbasecomponent, int i, int j, int k) {
+        this.a = packetplayouttitle_enumtitleaction;
+        this.b = ichatbasecomponent;
+        this.c = i;
+        this.d = j;
+        this.e = k;
+    }
+
+    public void a(PacketDataSerializer packetdataserializer) throws IOException {
+        this.a = (PacketPlayOutTitle.EnumTitleAction) packetdataserializer.a(PacketPlayOutTitle.EnumTitleAction.class);
+        if (this.a == PacketPlayOutTitle.EnumTitleAction.TITLE || this.a == PacketPlayOutTitle.EnumTitleAction.SUBTITLE) {
+            this.b = packetdataserializer.f();
+        }
+
+        if (this.a == PacketPlayOutTitle.EnumTitleAction.TIMES) {
+            this.c = packetdataserializer.readInt();
+            this.d = packetdataserializer.readInt();
+            this.e = packetdataserializer.readInt();
+        }
+
+    }
+
+    public void b(PacketDataSerializer packetdataserializer) throws IOException {
+        packetdataserializer.a((Enum) this.a);
+        if (this.a == PacketPlayOutTitle.EnumTitleAction.TITLE || this.a == PacketPlayOutTitle.EnumTitleAction.SUBTITLE) {
+            packetdataserializer.a(this.b);
+        }
+
+        if (this.a == PacketPlayOutTitle.EnumTitleAction.TIMES) {
+            packetdataserializer.writeInt(this.c);
+            packetdataserializer.writeInt(this.d);
+            packetdataserializer.writeInt(this.e);
+        }
+
+    }
+
+    public void a(PacketListenerPlayOut packetlistenerplayout) {
+        packetlistenerplayout.a(this);
+    }
+
+    public static enum EnumTitleAction {
+
+        TITLE, SUBTITLE, TIMES, CLEAR, RESET;
+
+        private EnumTitleAction() {}
+
+        public static PacketPlayOutTitle.EnumTitleAction a(String s) {
+            PacketPlayOutTitle.EnumTitleAction[] apacketplayouttitle_enumtitleaction = values();
+            int i = apacketplayouttitle_enumtitleaction.length;
+
+            for (int j = 0; j < i; ++j) {
+                PacketPlayOutTitle.EnumTitleAction packetplayouttitle_enumtitleaction = apacketplayouttitle_enumtitleaction[j];
+
+                if (packetplayouttitle_enumtitleaction.name().equalsIgnoreCase(s)) {
+                    return packetplayouttitle_enumtitleaction;
+                }
+            }
+
+            return PacketPlayOutTitle.EnumTitleAction.TITLE;
+        }
+
+        public static String[] a() {
+            String[] astring = new String[values().length];
+            int i = 0;
+            PacketPlayOutTitle.EnumTitleAction[] apacketplayouttitle_enumtitleaction = values();
+            int j = apacketplayouttitle_enumtitleaction.length;
+
+            for (int k = 0; k < j; ++k) {
+                PacketPlayOutTitle.EnumTitleAction packetplayouttitle_enumtitleaction = apacketplayouttitle_enumtitleaction[k];
+
+                astring[i++] = packetplayouttitle_enumtitleaction.name().toLowerCase();
+            }
+
+            return astring;
+        }
+    }
+}
-- 
2.7.3